From jython-checkins at python.org Sat Jan 3 21:20:19 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Sat, 03 Jan 2015 20:20:19 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Removed_unused_imports_in_G?= =?utf-8?q?eneric=2Ejava_and_fixed_some_warnings=2E?= Message-ID: <20150103202016.125906.90786@psf.io> https://hg.python.org/jython/rev/7516a8779510 changeset: 7493:7516a8779510 user: Stefan Richthofer date: Sat Jan 03 21:20:07 2015 +0100 summary: Removed unused imports in Generic.java and fixed some warnings. files: Lib/test/regrtest.py | 3 +++ src/org/python/util/Generic.java | 14 +++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1314,6 +1314,9 @@ test_peepholer test_pyclbr test_pyexpat + test_select + test_select_new + test_socket test_stringprep test_threadsignals test_transformer diff --git a/src/org/python/util/Generic.java b/src/org/python/util/Generic.java --- a/src/org/python/util/Generic.java +++ b/src/org/python/util/Generic.java @@ -1,19 +1,12 @@ package org.python.util; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.util.AbstractSet; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -39,11 +32,13 @@ public static List list() { return new ArrayList(); } + /** * Makes a List with its generic type inferred from whatever it's being assigned to filled with * the items in contents. */ - public static List list(U...contents) { + @SafeVarargs + public static List list(U... contents) { List l = new ArrayList(contents.length); for (T t : contents) { l.add(t); @@ -78,7 +73,8 @@ * Makes a Set using the generic type inferred from whatever this is being assigned to filled * with the items in contents. */ - public static Set set(U...contents) { + @SafeVarargs + public static Set set(U... contents) { Set s = new HashSet(contents.length); for (U u : contents) { s.add(u); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Jan 3 21:25:11 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Sat, 03 Jan 2015 20:25:11 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Reverted_accidental_changes?= =?utf-8?q?_in_regrtest=2Epy=3B_these_were_ment_to_be_temporary_and?= Message-ID: <20150103202511.72561.53740@psf.io> https://hg.python.org/jython/rev/c589be3c9ce8 changeset: 7494:c589be3c9ce8 user: Stefan Richthofer date: Sat Jan 03 21:24:55 2015 +0100 summary: Reverted accidental changes in regrtest.py; these were ment to be temporary and should have been reverted before the commit. files: Lib/test/regrtest.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1314,9 +1314,6 @@ test_peepholer test_pyclbr test_pyexpat - test_select - test_select_new - test_socket test_stringprep test_threadsignals test_transformer -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Jan 4 00:10:31 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Sat, 03 Jan 2015 23:10:31 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Repaired_indentation_in_PyJ?= =?utf-8?q?avaType=2Ejava=2C_replaced_several_tabs_with_spaces_plus?= Message-ID: <20150103231029.125906.1090@psf.io> https://hg.python.org/jython/rev/48018beb0596 changeset: 7495:48018beb0596 user: Stefan Richthofer date: Sun Jan 04 00:10:22 2015 +0100 summary: Repaired indentation in PyJavaType.java, replaced several tabs with spaces plus various minor cosmetics. files: src/org/python/core/PyJavaType.java | 119 +++++++-------- 1 files changed, 57 insertions(+), 62 deletions(-) diff --git a/src/org/python/core/PyJavaType.java b/src/org/python/core/PyJavaType.java --- a/src/org/python/core/PyJavaType.java +++ b/src/org/python/core/PyJavaType.java @@ -69,7 +69,6 @@ java.util.concurrent.TimeUnit.class); - /** * Other Java classes this type has MRO conflicts with. This doesn't matter for Java method * resolution, but if Python methods are added to the type, the added methods can't overlap with @@ -233,7 +232,7 @@ underlying_class = forClass; computeLinearMro(baseClass); } else { - needsInners.add(this); + needsInners.add(this); javaProxy = forClass; objtype = PyType.fromClassSkippingInners(Class.class, needsInners); // Wrapped Java types fill in their mro first using all of their interfaces then their @@ -547,6 +546,7 @@ } } } + if (ClassDictInit.class.isAssignableFrom(forClass) && forClass != ClassDictInit.class) { try { Method m = forClass.getMethod("classDictInit", PyObject.class); @@ -560,6 +560,7 @@ throw Py.JavaError(exc); } } + if (baseClass != Object.class) { hasGet = getDescrMethod(forClass, "__get__", OO) != null || getDescrMethod(forClass, "_doget", PyObject.class) != null @@ -569,8 +570,8 @@ hasDelete = getDescrMethod(forClass, "__delete__", PyObject.class) != null || getDescrMethod(forClass, "_dodel", PyObject.class) != null; } + if (forClass == Object.class) { - addMethod(new PyBuiltinMethodNarrow("__copy__") { @Override public PyObject __call__() { @@ -578,7 +579,6 @@ + "Consider monkeypatching __copy__ for " + self.getType().fastGetName()); } }); - addMethod(new PyBuiltinMethodNarrow("__deepcopy__") { @Override public PyObject __call__(PyObject memo) { @@ -586,7 +586,6 @@ + "Consider monkeypatching __deepcopy__ for " + self.getType().fastGetName()); } }); - addMethod(new PyBuiltinMethodNarrow("__eq__", 1) { @Override public PyObject __call__(PyObject o) { @@ -627,6 +626,7 @@ } }); } + if(forClass == Comparable.class) { addMethod(new ComparableMethod("__lt__", 1) { @Override @@ -654,11 +654,8 @@ }); } - if (immutableClasses.contains(forClass)) { - // __deepcopy__ just works for these objects since it uses serialization instead - addMethod(new PyBuiltinMethodNarrow("__copy__") { @Override public PyObject __call__() { @@ -673,8 +670,9 @@ public PyObject __call__() { Object obj = self.getJavaProxy(); Method clone; - // TODO we could specialize so that for well known objects like collections. This would avoid needing to use reflection - // in the general case, because Object#clone is protected (but most subclasses are not). + // TODO we could specialize so that for well known objects like collections. + // This would avoid needing to use reflection in the general case, + // because Object#clone is protected (but most subclasses are not). // // Lastly we can potentially cache the method handle in the proxy instead of looking it up each time try { @@ -687,7 +685,7 @@ } }); } - + if(forClass == Serializable.class) { addMethod(new PyBuiltinMethodNarrow("__deepcopy__") { @Override @@ -701,7 +699,6 @@ } } }); - } } @@ -709,67 +706,66 @@ // http://weblogs.java.net/blog/emcmanus/archive/2007/04/cloning_java_ob.html // blog post on deep cloning through serialization - // just what we need for __deepcopy__ support of Java objects + private static T cloneX(T x) throws IOException, ClassNotFoundException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + CloneOutput cout = new CloneOutput(bout); + cout.writeObject(x); + byte[] bytes = bout.toByteArray(); - private static T cloneX(T x) throws IOException, ClassNotFoundException { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - CloneOutput cout = new CloneOutput(bout); - cout.writeObject(x); - byte[] bytes = bout.toByteArray(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bytes); - CloneInput cin = new CloneInput(bin, cout); + ByteArrayInputStream bin = new ByteArrayInputStream(bytes); + CloneInput cin = new CloneInput(bin, cout); - @SuppressWarnings("unchecked") // thanks to Bas de Bakker for the tip! - T clone = (T) cin.readObject(); - return clone; + @SuppressWarnings("unchecked") // thanks to Bas de Bakker for the tip! + T clone = (T) cin.readObject(); + return clone; } private static class CloneOutput extends ObjectOutputStream { - Queue> classQueue = new LinkedList>(); + Queue> classQueue = new LinkedList>(); - CloneOutput(OutputStream out) throws IOException { - super(out); - } + CloneOutput(OutputStream out) throws IOException { + super(out); + } - @Override - protected void annotateClass(Class c) { - classQueue.add(c); - } + @Override + protected void annotateClass(Class c) { + classQueue.add(c); + } - @Override - protected void annotateProxyClass(Class c) { - classQueue.add(c); - } + @Override + protected void annotateProxyClass(Class c) { + classQueue.add(c); + } } private static class CloneInput extends ObjectInputStream { - private final CloneOutput output; + private final CloneOutput output; - CloneInput(InputStream in, CloneOutput output) throws IOException { - super(in); - this.output = output; - } + CloneInput(InputStream in, CloneOutput output) throws IOException { + super(in); + this.output = output; + } - @Override - protected Class resolveClass(ObjectStreamClass osc) - throws IOException, ClassNotFoundException { - Class c = output.classQueue.poll(); - String expected = osc.getName(); - String found = (c == null) ? null : c.getName(); - if (!expected.equals(found)) { - throw new InvalidClassException("Classes desynchronized: " + - "found " + found + " when expecting " + expected); - } - return c; - } + @Override + protected Class resolveClass(ObjectStreamClass osc) + throws IOException, ClassNotFoundException { + Class c = output.classQueue.poll(); + String expected = osc.getName(); + String found = (c == null) ? null : c.getName(); + if (!expected.equals(found)) { + throw new InvalidClassException("Classes desynchronized: " + + "found " + found + " when expecting " + expected); + } + return c; + } - @Override - protected Class resolveProxyClass(String[] interfaceNames) - throws IOException, ClassNotFoundException { - return output.classQueue.poll(); - } + @Override + protected Class resolveProxyClass(String[] interfaceNames) + throws IOException, ClassNotFoundException { + return output.classQueue.poll(); + } } - + /** * Private, protected or package protected classes that implement public interfaces or extend * public classes can't have their implementations of the methods of their supertypes called @@ -865,7 +861,6 @@ } private static class EnumerationIter extends PyIterator { - private Enumeration proxy; public EnumerationIter(Enumeration proxy) { @@ -878,9 +873,11 @@ } private static abstract class ComparableMethod extends PyBuiltinMethodNarrow { + protected ComparableMethod(String name, int numArgs) { super(name, numArgs); } + @Override public PyObject __call__(PyObject arg) { Object asjava = arg.__tojava__(Object.class); @@ -942,7 +939,6 @@ return Py.newInteger(((Collection) self.getJavaProxy()).size()); } }; - PyBuiltinMethodNarrow containsProxy = new PyBuiltinMethodNarrow("__contains__", 1) { @Override public PyObject __call__(PyObject obj) { @@ -963,8 +959,7 @@ return contained ? Py.True : Py.False; } }; - proxies.put(Collection.class, new PyBuiltinMethod[]{lenProxy, - containsProxy}); + proxies.put(Collection.class, new PyBuiltinMethod[]{lenProxy, containsProxy}); PyBuiltinMethodNarrow iteratorProxy = new PyBuiltinMethodNarrow("__iter__") { @Override -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Jan 4 17:51:58 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 04 Jan 2015 16:51:58 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_os=2Egetenv=2C_os=2Elistdir?= =?utf-8?q?_may_return_unicode_instead_of_bytes?= Message-ID: <20150104165123.8767.26523@psf.io> https://hg.python.org/jython/rev/ea036792f304 changeset: 7496:ea036792f304 user: Jim Baker date: Sun Jan 04 09:51:07 2015 -0700 summary: os.getenv, os.listdir may return unicode instead of bytes Note that now this deviates from CPython 2.7, although matches the behavior seen in Python 3.x. Here's why this is necessary: * Java does not support paths and environment entries (variables or values) not expressible in Unicode. Similar restrictions are seen in CPython 2.7: OS X does not support non Unicode directory names. * However Jython's raison d'?tre is seamless Java integration: it should be generally possible to mix Python and Java together, eg [java.io.File(p).exists() for p in os.listdir()] should always work. In general, this changeset should not have impact on user code, given that for code using Python 2, unicode and str/bytes can be freely mixed. For Jython specifically, os.listdir and functionality that builds on it like glob has been until now broken for Unicode paths (with codepoints > 255) since Jython 2.5. Fixes an urgent bug that Jython could not be started with a current working directory with a path using Unicode codepoints > 255, part of http://bugs.jython.org/issue2239 Completes an outstanding issue for OSError and Unicode paths, see http://bugs.jython.org/issue1825 files: Lib/test/test_genericpath.py | 256 ++++++++++ Lib/test/test_os_jy.py | 74 ++- Lib/test/test_support.py | 3 +- src/org/python/core/Py.java | 20 + src/org/python/modules/posix/PosixModule.java | 9 +- src/org/python/modules/posix/PyStatResult.java | 18 +- src/org/python/modules/posix/PythonPOSIXHandler.java | 9 +- 7 files changed, 374 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_genericpath.py @@ -0,0 +1,256 @@ +""" +Tests common to genericpath, macpath, ntpath and posixpath +""" + +import unittest +from test import test_support +import os +import genericpath +import sys + + +def safe_rmdir(dirname): + try: + os.rmdir(dirname) + except OSError: + pass + + +class GenericTest(unittest.TestCase): + # The path module to be tested + pathmodule = genericpath + common_attributes = ['commonprefix', 'getsize', 'getatime', 'getctime', + 'getmtime', 'exists', 'isdir', 'isfile'] + attributes = [] + + def test_no_argument(self): + for attr in self.common_attributes + self.attributes: + with self.assertRaises(TypeError): + getattr(self.pathmodule, attr)() + raise self.fail("{}.{}() did not raise a TypeError" + .format(self.pathmodule.__name__, attr)) + + def test_commonprefix(self): + commonprefix = self.pathmodule.commonprefix + self.assertEqual( + commonprefix([]), + "" + ) + self.assertEqual( + commonprefix(["/home/swenson/spam", "/home/swen/spam"]), + "/home/swen" + ) + self.assertEqual( + commonprefix(["/home/swen/spam", "/home/swen/eggs"]), + "/home/swen/" + ) + self.assertEqual( + commonprefix(["/home/swen/spam", "/home/swen/spam"]), + "/home/swen/spam" + ) + self.assertEqual( + commonprefix(["home:swenson:spam", "home:swen:spam"]), + "home:swen" + ) + self.assertEqual( + commonprefix([":home:swen:spam", ":home:swen:eggs"]), + ":home:swen:" + ) + self.assertEqual( + commonprefix([":home:swen:spam", ":home:swen:spam"]), + ":home:swen:spam" + ) + + testlist = ['', 'abc', 'Xbcd', 'Xb', 'XY', 'abcd', + 'aXc', 'abd', 'ab', 'aX', 'abcX'] + for s1 in testlist: + for s2 in testlist: + p = commonprefix([s1, s2]) + self.assertTrue(s1.startswith(p)) + self.assertTrue(s2.startswith(p)) + if s1 != s2: + n = len(p) + self.assertNotEqual(s1[n:n+1], s2[n:n+1]) + + def test_getsize(self): + f = open(test_support.TESTFN, "wb") + try: + f.write("foo") + f.close() + self.assertEqual(self.pathmodule.getsize(test_support.TESTFN), 3) + finally: + if not f.closed: + f.close() + test_support.unlink(test_support.TESTFN) + + def test_time(self): + f = open(test_support.TESTFN, "wb") + try: + f.write("foo") + f.close() + f = open(test_support.TESTFN, "ab") + f.write("bar") + f.close() + f = open(test_support.TESTFN, "rb") + d = f.read() + f.close() + self.assertEqual(d, "foobar") + + self.assertLessEqual( + self.pathmodule.getctime(test_support.TESTFN), + self.pathmodule.getmtime(test_support.TESTFN) + ) + finally: + if not f.closed: + f.close() + test_support.unlink(test_support.TESTFN) + + def test_exists(self): + self.assertIs(self.pathmodule.exists(test_support.TESTFN), False) + f = open(test_support.TESTFN, "wb") + try: + f.write("foo") + f.close() + self.assertIs(self.pathmodule.exists(test_support.TESTFN), True) + if not self.pathmodule == genericpath: + self.assertIs(self.pathmodule.lexists(test_support.TESTFN), + True) + finally: + if not f.close(): + f.close() + test_support.unlink(test_support.TESTFN) + + def test_isdir(self): + self.assertIs(self.pathmodule.isdir(test_support.TESTFN), False) + f = open(test_support.TESTFN, "wb") + try: + f.write("foo") + f.close() + self.assertIs(self.pathmodule.isdir(test_support.TESTFN), False) + os.remove(test_support.TESTFN) + os.mkdir(test_support.TESTFN) + self.assertIs(self.pathmodule.isdir(test_support.TESTFN), True) + os.rmdir(test_support.TESTFN) + finally: + if not f.close(): + f.close() + test_support.unlink(test_support.TESTFN) + safe_rmdir(test_support.TESTFN) + + def test_isfile(self): + self.assertIs(self.pathmodule.isfile(test_support.TESTFN), False) + f = open(test_support.TESTFN, "wb") + try: + f.write("foo") + f.close() + self.assertIs(self.pathmodule.isfile(test_support.TESTFN), True) + os.remove(test_support.TESTFN) + os.mkdir(test_support.TESTFN) + self.assertIs(self.pathmodule.isfile(test_support.TESTFN), False) + os.rmdir(test_support.TESTFN) + finally: + if not f.close(): + f.close() + test_support.unlink(test_support.TESTFN) + safe_rmdir(test_support.TESTFN) + + +# Following TestCase is not supposed to be run from test_genericpath. +# It is inherited by other test modules (macpath, ntpath, posixpath). + +class CommonTest(GenericTest): + # The path module to be tested + pathmodule = None + common_attributes = GenericTest.common_attributes + [ + # Properties + 'curdir', 'pardir', 'extsep', 'sep', + 'pathsep', 'defpath', 'altsep', 'devnull', + # Methods + 'normcase', 'splitdrive', 'expandvars', 'normpath', 'abspath', + 'join', 'split', 'splitext', 'isabs', 'basename', 'dirname', + 'lexists', 'islink', 'ismount', 'expanduser', 'normpath', 'realpath', + ] + + def test_normcase(self): + # Check that normcase() is idempotent + p = "FoO/./BaR" + p = self.pathmodule.normcase(p) + self.assertEqual(p, self.pathmodule.normcase(p)) + + def test_splitdrive(self): + # splitdrive for non-NT paths + splitdrive = self.pathmodule.splitdrive + self.assertEqual(splitdrive("/foo/bar"), ("", "/foo/bar")) + self.assertEqual(splitdrive("foo:bar"), ("", "foo:bar")) + self.assertEqual(splitdrive(":foo:bar"), ("", ":foo:bar")) + + def test_expandvars(self): + if self.pathmodule.__name__ == 'macpath': + self.skipTest('macpath.expandvars is a stub') + expandvars = self.pathmodule.expandvars + with test_support.EnvironmentVarGuard() as env: + env.clear() + env["foo"] = "bar" + env["{foo"] = "baz1" + env["{foo}"] = "baz2" + self.assertEqual(expandvars("foo"), "foo") + self.assertEqual(expandvars("$foo bar"), "bar bar") + self.assertEqual(expandvars("${foo}bar"), "barbar") + self.assertEqual(expandvars("$[foo]bar"), "$[foo]bar") + self.assertEqual(expandvars("$bar bar"), "$bar bar") + self.assertEqual(expandvars("$?bar"), "$?bar") + self.assertEqual(expandvars("${foo}bar"), "barbar") + self.assertEqual(expandvars("$foo}bar"), "bar}bar") + self.assertEqual(expandvars("${foo"), "${foo") + self.assertEqual(expandvars("${{foo}}"), "baz1}") + self.assertEqual(expandvars("$foo$foo"), "barbar") + self.assertEqual(expandvars("$bar$bar"), "$bar$bar") + + def test_abspath(self): + self.assertIn("foo", self.pathmodule.abspath("foo")) + + # Abspath returns bytes when the arg is bytes + for path in ('', 'foo', 'f\xf2\xf2', '/foo', 'C:\\'): + self.assertIsInstance(self.pathmodule.abspath(path), str) + + def test_realpath(self): + self.assertIn("foo", self.pathmodule.realpath("foo")) + + def test_normpath_issue5827(self): + # Make sure normpath preserves unicode + for path in (u'', u'.', u'/', u'\\', u'///foo/.//bar//'): + self.assertIsInstance(self.pathmodule.normpath(path), unicode) + + def test_abspath_issue3426(self): + # Check that abspath returns unicode when the arg is unicode + # with both ASCII and non-ASCII cwds. + abspath = self.pathmodule.abspath + for path in (u'', u'fuu', u'f\xf9\xf9', u'/fuu', u'U:\\'): + self.assertIsInstance(abspath(path), unicode) + + unicwd = u'\xe7w\xf0' + try: + fsencoding = test_support.TESTFN_ENCODING or "ascii" + unicwd.encode(fsencoding) + except (AttributeError, UnicodeEncodeError): + # FS encoding is probably ASCII + pass + else: + with test_support.temp_cwd(unicwd): + for path in (u'', u'fuu', u'f\xf9\xf9', u'/fuu', u'U:\\'): + self.assertIsInstance(abspath(path), unicode) + + @unittest.skipIf(sys.platform == 'darwin' or test_support.is_jython, + "Both Mac OS X and Java deny the creation of a directory with an invalid utf8 name") + def test_nonascii_abspath(self): + # Test non-ASCII, non-UTF8 bytes in the path. + with test_support.temp_cwd('\xe7w\xf0'): + self.test_abspath() + + +def test_main(): + test_support.run_unittest(GenericTest) + + +if __name__=="__main__": + test_main() diff --git a/Lib/test/test_os_jy.py b/Lib/test/test_os_jy.py --- a/Lib/test/test_os_jy.py +++ b/Lib/test/test_os_jy.py @@ -1,11 +1,18 @@ +# -*- coding: utf-8 -*- + """Misc os module tests Made for Jython. """ +import array +import glob import os -import array +import subprocess +import sys import unittest from test import test_support +from java.io import File + class OSFileTestCase(unittest.TestCase): @@ -121,6 +128,70 @@ # lacks buffer api: self.assertRaises(TypeError, self.do_write, 1.5, 4) +class OSUnicodeTestCase(unittest.TestCase): + + def test_env(self): + with test_support.temp_cwd(name=u"tempcwd-??"): + newenv = os.environ.copy() + newenv["TEST_HOME"] = u"??" + p = subprocess.Popen([sys.executable, "-c", + 'import sys,os;' \ + 'sys.stdout.write(os.getenv("TEST_HOME").encode("utf-8"))'], + stdout=subprocess.PIPE, + env=newenv) + self.assertEqual(p.stdout.read().decode("utf-8"), u"??") + + def test_getcwd(self): + with test_support.temp_cwd(name=u"tempcwd-??") as temp_cwd: + p = subprocess.Popen([sys.executable, "-c", + 'import sys,os;' \ + 'sys.stdout.write(os.getcwd().encode("utf-8"))'], + stdout=subprocess.PIPE) + self.assertEqual(p.stdout.read().decode("utf-8"), temp_cwd) + + def test_listdir(self): + # It is hard to avoid Unicode paths on systems like OS X. Use + # relative paths from a temp CWD to work around this + with test_support.temp_cwd() as new_cwd: + unicode_path = os.path.join(".", "unicode") + self.assertIs(type(unicode_path), str) + chinese_path = os.path.join(unicode_path, u"??") + self.assertIs(type(chinese_path), unicode) + home_path = os.path.join(chinese_path, u"??") + os.makedirs(home_path) + + with open(os.path.join(home_path, "test.txt"), "w") as test_file: + test_file.write("42\n") + + # Verify works with str paths, returning Unicode as necessary + entries = os.listdir(unicode_path) + self.assertIn(u"??", entries) + + # Verify works with Unicode paths + entries = os.listdir(chinese_path) + self.assertIn(u"??", entries) + + # glob.glob builds on os.listdir; note that we don't use + # Unicode paths in the arg to glob + self.assertEqual(glob.glob("unicode/*"), [u"unicode/??"]) + self.assertEqual(glob.glob("unicode/*/*"), [u"unicode/??/??"]) + self.assertEqual(glob.glob("unicode/*/*/*"), [u"unicode/??/??/test.txt"]) + + # Now use a Unicode path as well as the glob arg + self.assertEqual(glob.glob(u"unicode/*"), [u"unicode/??"]) + self.assertEqual(glob.glob(u"unicode/*/*"), [u"unicode/??/??"]) + self.assertEqual(glob.glob(u"unicode/*/*/*"), [u"unicode/??/??/test.txt"]) + + # Verify Java integration. But we will need to construct + # an absolute path since chdir doesn't work with Java + # (except for subprocesses, like below in test_env) + for entry in entries: + entry_path = os.path.join(new_cwd, chinese_path, entry) + f = File(entry_path) + self.assertTrue(f.exists(), "File %r (%r) should be testable for existence" % ( + f, entry_path)) + + def test_main(): test_support.run_unittest( @@ -128,6 +199,7 @@ OSDirTestCase, OSStatTestCase, OSWriteTestCase, + OSUnicodeTestCase ) if __name__ == '__main__': diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -528,7 +528,8 @@ the CWD, an error is raised. If it's True, only a warning is raised and the original CWD is used. """ - if have_unicode and isinstance(name, unicode): + if have_unicode and isinstance(name, unicode) and not is_jython: + # Jython supports unicode paths try: name = name.encode(sys.getfilesystemencoding() or 'ascii') except UnicodeEncodeError: diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Set; +import com.google.common.base.CharMatcher; import jnr.constants.Constant; import jnr.constants.platform.Errno; import jnr.posix.POSIX; @@ -626,6 +627,25 @@ return new PyString(s); } + // Use if s may contain Unicode characters, + // but we prefer to return a PyString + public static PyString newStringOrUnicode(String s) { + return newStringOrUnicode(Py.EmptyString, s); + } + + // Use when returning a PyString or PyUnicode is based on what "kind" is, + // but always fallback to PyUnicode if s contains Unicode characters. + public static PyString newStringOrUnicode(PyObject kind, String s) { + if (kind instanceof PyUnicode) { + return Py.newUnicode(s); + } + if (CharMatcher.ASCII.matchesAllOf(s)) { + return Py.newString(s); + } else { + return Py.newUnicode(s); + } + } + public static PyStringMap newStringMap() { // enable lazy bootstrapping (see issue #1671) if (!PyType.hasBuilder(PyStringMap.class)) { diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java --- a/src/org/python/modules/posix/PosixModule.java +++ b/src/org/python/modules/posix/PosixModule.java @@ -316,7 +316,7 @@ "getcwd() -> path\n\n" + "Return a string representing the current working directory."); public static PyObject getcwd() { - return Py.newString(Py.getSystemState().getCurrentWorkingDir()); + return Py.newStringOrUnicode(Py.getSystemState().getCurrentWorkingDir()); } public static PyString __doc__getcwdu = new PyString( @@ -494,9 +494,8 @@ } PyList list = new PyList(); - PyString string = (PyString) path; for (String name : names) { - list.append(string.createInstance(name)); + list.append(Py.newStringOrUnicode(path, name)); } return list; } @@ -893,7 +892,9 @@ return environ; } for (Map.Entry entry : env.entrySet()) { - environ.__setitem__(Py.newString(entry.getKey()), Py.newString(entry.getValue())); + environ.__setitem__( + Py.newStringOrUnicode(entry.getKey()), + Py.newStringOrUnicode(entry.getValue())); } return environ; } diff --git a/src/org/python/modules/posix/PyStatResult.java b/src/org/python/modules/posix/PyStatResult.java --- a/src/org/python/modules/posix/PyStatResult.java +++ b/src/org/python/modules/posix/PyStatResult.java @@ -8,6 +8,7 @@ import org.python.core.PyList; import org.python.core.PyNewWrapper; import org.python.core.PyObject; +import org.python.core.PyString; import org.python.core.PyTuple; import org.python.core.PyType; @@ -75,12 +76,17 @@ /** * Return a Python stat result from a posix layer FileStat object. + * + * Ideally times would be returned as floats, like CPython, however, the underlying FileStat + * object from JNR Posix only has integer resolution. + * + * We should be able to resolve by using java.nio.file.attribute.PosixFileAttributeView */ public static PyStatResult fromFileStat(FileStat stat) { - return new PyStatResult(Py.newInteger(stat.mode()), Py.newLong(stat.ino()), + return new PyStatResult(Py.newInteger(stat.mode()), Py.newInteger(stat.ino()), Py.newLong(stat.dev()), Py.newInteger(stat.nlink()), Py.newInteger(stat.uid()), Py.newInteger(stat.gid()), - Py.newLong(stat.st_size()), Py.newInteger(stat.atime()), + Py.newInteger(stat.st_size()), Py.newInteger(stat.atime()), Py.newInteger(stat.mtime()), Py.newInteger(stat.ctime())); } @@ -137,4 +143,12 @@ public PyTuple __getnewargs__() { return new PyTuple(new PyList(getArray())); } + + @Override + public PyString __repr__() { + return (PyString) Py.newString( + "posix.stat_result(" + + "st_mode=%r, st_ino=%r, st_dev=%r, st_nlink=%r, st_uid=%r, "+ + "st_gid=%r, st_size=%r, st_atime=%r, st_mtime=%r, st_ctime=%r)").__mod__(this); + } } diff --git a/src/org/python/modules/posix/PythonPOSIXHandler.java b/src/org/python/modules/posix/PythonPOSIXHandler.java --- a/src/org/python/modules/posix/PythonPOSIXHandler.java +++ b/src/org/python/modules/posix/PythonPOSIXHandler.java @@ -6,7 +6,6 @@ import java.io.PrintStream; import jnr.constants.platform.Errno; -import jnr.posix.POSIX; import jnr.posix.POSIXHandler; import org.python.core.imp; @@ -21,15 +20,11 @@ public class PythonPOSIXHandler implements POSIXHandler { public void error(Errno error, String extraData) { - // XXX: extraData (filename) could have been unicode! - // http://bugs.jython.org/issue1825 - throw Py.OSError(error, Py.newString(extraData)); + throw Py.OSError(error, Py.newStringOrUnicode(extraData)); } public void error(Errno error, String methodName, String extraData) { - // XXX: extraData (filename) could have been unicode! - // http://bugs.jython.org/issue1825 - throw Py.OSError(error, Py.newString(extraData)); + throw Py.OSError(error, Py.newStringOrUnicode(extraData)); } public void unimplementedError(String methodName) { -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 5 01:58:49 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 05 Jan 2015 00:58:49 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_Java_Native_Runtime_?= =?utf-8?q?jars?= Message-ID: <20150105005844.11583.95277@psf.io> https://hg.python.org/jython/rev/63d850f63e6f changeset: 7497:63d850f63e6f user: Jim Baker date: Sun Jan 04 17:58:15 2015 -0700 summary: Update Java Native Runtime jars Update Java Native Runtime jars to latest versions. Finalizes fix for http://bugs.jython.org/issue2110 files: build.xml | 20 ++++++++++---------- extlibs/jffi-1.2.6.jar | Bin extlibs/jffi-1.2.7.jar | Bin extlibs/jnr-constants-0.8.4.jar | Bin extlibs/jnr-constants-0.8.6.jar | Bin extlibs/jnr-ffi-0.7.10.jar | Bin extlibs/jnr-ffi-2.0.1.jar | Bin extlibs/jnr-netdb-1.1.1.jar | Bin extlibs/jnr-netdb-1.1.4.jar | Bin extlibs/jnr-posix-2.4.0.jar | Bin extlibs/jnr-posix-3.0.9.jar | Bin 11 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -173,11 +173,11 @@ - - - - - + + + + + @@ -613,11 +613,11 @@ - - - - - + + + + + diff --git a/extlibs/jffi-1.2.6.jar b/extlibs/jffi-1.2.6.jar deleted file mode 100644 index a6b2be6c39798f0fc5958aa309924506b74f0f9f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jffi-1.2.7.jar b/extlibs/jffi-1.2.7.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..68c8db05c248ab54aba86d03d3c7904334468770 GIT binary patch [stripped] diff --git a/extlibs/jnr-constants-0.8.4.jar b/extlibs/jnr-constants-0.8.4.jar deleted file mode 100644 index f0ff6bb1a1796560c09121b4366a5d04032156af..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jnr-constants-0.8.6.jar b/extlibs/jnr-constants-0.8.6.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0be41ffb6b2b9fab25df0f451125b74749b5a5c3 GIT binary patch [stripped] diff --git a/extlibs/jnr-ffi-0.7.10.jar b/extlibs/jnr-ffi-0.7.10.jar deleted file mode 100644 index 9e2e64f276334bed30c62d12823d5088b5672425..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jnr-ffi-2.0.1.jar b/extlibs/jnr-ffi-2.0.1.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..52b6f3c0692a69b5ba9c20fb32b9fc8293810c67 GIT binary patch [stripped] diff --git a/extlibs/jnr-netdb-1.1.1.jar b/extlibs/jnr-netdb-1.1.1.jar deleted file mode 100644 index 731f6ec0fdc5c420ec55edec6c28092b06c70e32..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jnr-netdb-1.1.4.jar b/extlibs/jnr-netdb-1.1.4.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d5bddf3d1c075f27b57f5032246bd568514c45b1 GIT binary patch [stripped] diff --git a/extlibs/jnr-posix-2.4.0.jar b/extlibs/jnr-posix-2.4.0.jar deleted file mode 100644 index 36f3fc1d217091941a1079e9ebccc70094a5ede6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jnr-posix-3.0.9.jar b/extlibs/jnr-posix-3.0.9.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..182bdc4a34f160c8e165298576b740ffb95a1d81 GIT binary patch [stripped] -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 5 02:56:18 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 05 Jan 2015 01:56:18 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_other_supporting_jar?= =?utf-8?q?s?= Message-ID: <20150105015226.11571.88334@psf.io> https://hg.python.org/jython/rev/ab989b7380c3 changeset: 7498:ab989b7380c3 user: Jim Baker date: Sun Jan 04 18:51:44 2015 -0700 summary: Update other supporting jars Update Apache Commons Compression, Google Guava, ICU4J, and Netty 4 to latest released jars. files: build.xml | 29 ++++++---- extlibs/commons-compress-1.8.1.jar | Bin extlibs/commons-compress-1.9.jar | Bin extlibs/guava-17.0.jar | Bin extlibs/guava-18.0.jar | Bin extlibs/icu4j-52_1.jar | Bin extlibs/icu4j-54_1_1.jar | Bin extlibs/netty-buffer-4.0.20.Final.jar | Bin extlibs/netty-buffer-4.0.25.Final.jar | Bin extlibs/netty-codec-4.0.20.Final.jar | Bin extlibs/netty-codec-4.0.25.Final.jar | Bin extlibs/netty-common-4.0.20.Final.jar | Bin extlibs/netty-common-4.0.25.Final.jar | Bin extlibs/netty-handler-4.0.20.Final.jar | Bin extlibs/netty-handler-4.0.25.Final.jar | Bin extlibs/netty-transport-4.0.20.Final.jar | Bin extlibs/netty-transport-4.0.25.Final.jar | Bin 17 files changed, 17 insertions(+), 12 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -149,12 +149,12 @@ - + - - + + @@ -178,7 +178,12 @@ - + + + + + + @@ -579,21 +584,21 @@ - + - + - + - + - + - + - + - + diff --git a/extlibs/commons-compress-1.8.1.jar b/extlibs/commons-compress-1.8.1.jar deleted file mode 100644 index 66b0a56bd8b24478ddeb2d6eb2824280de1c1a9d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/commons-compress-1.9.jar b/extlibs/commons-compress-1.9.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14e7e868e80da57f6a1f9f0bb5211a450b153805 GIT binary patch [stripped] diff --git a/extlibs/guava-17.0.jar b/extlibs/guava-17.0.jar deleted file mode 100644 index 661fc7473f8760f5f81874ddc1fcc0b5634fd6cf..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/guava-18.0.jar b/extlibs/guava-18.0.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8f89e490180121500dfb1e65b3ebd8f1a7a4c3b1 GIT binary patch [stripped] diff --git a/extlibs/icu4j-52_1.jar b/extlibs/icu4j-52_1.jar deleted file mode 100644 index 49a4b802561cb56c7dc476ff40e23779a978e0c9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/icu4j-54_1_1.jar b/extlibs/icu4j-54_1_1.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ded7cebf8d1a3d9589f7a3efb6a74f485cb0c715 GIT binary patch [stripped] diff --git a/extlibs/netty-buffer-4.0.20.Final.jar b/extlibs/netty-buffer-4.0.20.Final.jar deleted file mode 100644 index 0ac294bfdbcda2224d025ddb146b58284bfc0525..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-buffer-4.0.25.Final.jar b/extlibs/netty-buffer-4.0.25.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..de8fa8e44ed46356174579086a545f043d0d225c GIT binary patch [stripped] diff --git a/extlibs/netty-codec-4.0.20.Final.jar b/extlibs/netty-codec-4.0.20.Final.jar deleted file mode 100644 index 4d4d3a99aca2b16b2df6558d4051fdc53219e8cc..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-codec-4.0.25.Final.jar b/extlibs/netty-codec-4.0.25.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f1a618c8f1c02025ad202d53a3d9894f703abf5d GIT binary patch [stripped] diff --git a/extlibs/netty-common-4.0.20.Final.jar b/extlibs/netty-common-4.0.20.Final.jar deleted file mode 100644 index 421956e0a7fbc901d50ac8ef03eadb639235d986..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-common-4.0.25.Final.jar b/extlibs/netty-common-4.0.25.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f23daacc18d360fa782bf5bb355034da77408cf5 GIT binary patch [stripped] diff --git a/extlibs/netty-handler-4.0.20.Final.jar b/extlibs/netty-handler-4.0.20.Final.jar deleted file mode 100644 index 636e0c957874f623954b06c6992d7188f21de0a2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-handler-4.0.25.Final.jar b/extlibs/netty-handler-4.0.25.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b1c61f2ce65544cc6b9643c9cbe931882f0450b2 GIT binary patch [stripped] diff --git a/extlibs/netty-transport-4.0.20.Final.jar b/extlibs/netty-transport-4.0.20.Final.jar deleted file mode 100644 index 0aeebc30bbc977bb212c1c2e8b3dce7838117f7b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-transport-4.0.25.Final.jar b/extlibs/netty-transport-4.0.25.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2edc97363251cb88ed2eae2d44bea1a4e43602fb GIT binary patch [stripped] -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 5 05:33:01 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Mon, 05 Jan 2015 04:33:01 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Repaired_build=2Exml_so_tha?= =?utf-8?q?t_=27ant_jar-standalone=27_works_again=2E?= Message-ID: <20150105043255.22405.37892@psf.io> https://hg.python.org/jython/rev/86465a524ce2 changeset: 7499:86465a524ce2 user: Stefan Richthofer date: Mon Jan 05 05:32:47 2015 +0100 summary: Repaired build.xml so that 'ant jar-standalone' works again. files: build.xml | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -154,7 +154,7 @@ - + @@ -588,7 +588,7 @@ - + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 5 18:14:58 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 05 Jan 2015 17:14:58 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Updated_ASM_to_5=2E0=2E3_fo?= =?utf-8?q?r_Java_8_support?= Message-ID: <20150105171431.72563.58349@psf.io> https://hg.python.org/jython/rev/cd3fe8336fb2 changeset: 7500:cd3fe8336fb2 user: Jim Baker date: Mon Jan 05 10:14:22 2015 -0700 summary: Updated ASM to 5.0.3 for Java 8 support Using ASM 4 to target Java 8 works for code generation, but not for code introspection, such as analyzing jars or supporting Clamp. Fixed by upgrading to ASM 5. Replaced Jython-specific code to analyze access permissions from a classfile in favor of ASM. For Jython developers working on code compilation: when emitting bytecode, if you are visiting a method that's owned by an interface (not implemented by a class), you need to use different visitMethodInsn. See the change in CodeCompiler#visitWith - the only change that was currently required. Bumped bytecode magic. files: build.xml | 12 +- extlibs/asm-4.0.jar | Bin extlibs/asm-5.0.3.jar | Bin extlibs/asm-commons-4.0.jar | Bin extlibs/asm-commons-5.0.3.jar | Bin extlibs/asm-util-4.0.jar | Bin extlibs/asm-util-5.0.3.jar | Bin src/org/python/compiler/Code.java | 18 +- src/org/python/compiler/CodeCompiler.java | 6 +- src/org/python/compiler/JavaMaker.java | 2 +- src/org/python/compiler/ProxyMaker.java | 2 +- src/org/python/core/AnnotationReader.java | 11 +- src/org/python/core/imp.java | 2 +- src/org/python/core/packagecache/PackageManager.java | 92 +++------ src/org/python/expose/generate/ExposedFieldFinder.java | 2 +- src/org/python/expose/generate/ExposedMethodFinder.java | 2 +- src/org/python/expose/generate/ExposedTypeProcessor.java | 17 +- src/org/python/expose/generate/Exposer.java | 6 +- src/org/python/expose/generate/RestrictiveAnnotationVisitor.java | 2 +- 19 files changed, 76 insertions(+), 98 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -150,9 +150,9 @@ - - - + + + @@ -576,9 +576,9 @@ - - - + + + diff --git a/extlibs/asm-4.0.jar b/extlibs/asm-4.0.jar deleted file mode 100644 index 6d63075eb7331f7120ef25603a2ade856d12f715..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/asm-5.0.3.jar b/extlibs/asm-5.0.3.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..573535b1d55acb9f787747dffb31231a0bcd9e59 GIT binary patch [stripped] diff --git a/extlibs/asm-commons-4.0.jar b/extlibs/asm-commons-4.0.jar deleted file mode 100644 index 8d564b1e029e7b4f5c984c3fa67293ded9962e5b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/asm-commons-5.0.3.jar b/extlibs/asm-commons-5.0.3.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..514a6dc2e1a8e94f0b6e32c2c8309300853a2110 GIT binary patch [stripped] diff --git a/extlibs/asm-util-4.0.jar b/extlibs/asm-util-4.0.jar deleted file mode 100644 index 0e1059583543a10cde82abfcfe3fbde37347c8a7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/asm-util-5.0.3.jar b/extlibs/asm-util-5.0.3.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e89f1b7b67e54e57b7e9ce062537292676bafb19 GIT binary patch [stripped] diff --git a/src/org/python/compiler/Code.java b/src/org/python/compiler/Code.java --- a/src/org/python/compiler/Code.java +++ b/src/org/python/compiler/Code.java @@ -22,7 +22,7 @@ //XXX: I'd really like to get sig and access out of here since MethodVistitor // should already have this information. public Code(MethodVisitor mv, String sig, int access) { - super(ASM4); + super(ASM5); this.mv = mv; this.sig = sig; nlocals = -sigSize(sig, false); @@ -153,8 +153,8 @@ mv.visitMaxs(arg0, arg1); } - public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) { - mv.visitMethodInsn(arg0, arg1, arg2, arg3); + public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3, boolean itf) { + mv.visitMethodInsn(arg0, arg1, arg2, arg3, itf); } public void visitMultiANewArrayInsn(String arg0, int arg1) { @@ -468,19 +468,23 @@ } public void invokeinterface(String owner, String name, String type) { - mv.visitMethodInsn(INVOKEINTERFACE, owner, name, type); + mv.visitMethodInsn(INVOKEINTERFACE, owner, name, type, false); + } + + public void invokeinterface(String owner, String name, String type, boolean itf) { + mv.visitMethodInsn(INVOKEINTERFACE, owner, name, type, itf); } public void invokespecial(String owner, String name, String type) { - mv.visitMethodInsn(INVOKESPECIAL, owner, name, type); + mv.visitMethodInsn(INVOKESPECIAL, owner, name, type, false); } public void invokestatic(String owner, String name, String type) { - mv.visitMethodInsn(INVOKESTATIC, owner, name, type); + mv.visitMethodInsn(INVOKESTATIC, owner, name, type, false); } public void invokevirtual(String owner, String name, String type) { - mv.visitMethodInsn(INVOKEVIRTUAL, owner, name, type); + mv.visitMethodInsn(INVOKEVIRTUAL, owner, name, type, false); } public void ireturn() { diff --git a/src/org/python/compiler/CodeCompiler.java b/src/org/python/compiler/CodeCompiler.java --- a/src/org/python/compiler/CodeCompiler.java +++ b/src/org/python/compiler/CodeCompiler.java @@ -2691,7 +2691,7 @@ // value = mgr.__enter__() loadThreadState(); code.invokeinterface(Type.getType(ContextManager.class).getInternalName(), - __enter__.getName(), __enter__.getDescriptor()); + __enter__.getName(), __enter__.getDescriptor(), true); int value_tmp = code.getLocal(p(PyObject.class)); code.astore(value_tmp); @@ -2716,7 +2716,7 @@ loadThreadState(); compiler.code.aconst_null(); compiler.code.invokeinterface(Type.getType(ContextManager.class).getInternalName(), - __exit__.getName(), __exit__.getDescriptor()); + __exit__.getName(), __exit__.getDescriptor(), true); compiler.code.pop(); } }; @@ -2761,7 +2761,7 @@ loadThreadState(); code.swap(); code.invokeinterface(Type.getType(ContextManager.class).getInternalName(), - __exit__.getName(), __exit__.getDescriptor()); + __exit__.getName(), __exit__.getDescriptor(), true); // # The exceptional case is handled here // exc = False # implicit diff --git a/src/org/python/compiler/JavaMaker.java b/src/org/python/compiler/JavaMaker.java --- a/src/org/python/compiler/JavaMaker.java +++ b/src/org/python/compiler/JavaMaker.java @@ -49,7 +49,7 @@ code.visitLdcInsn(pythonClass); code.visitVarInsn(ALOAD, 1); code.visitMethodInsn(INVOKESTATIC, "org/python/core/Py", "initProxy", - makeSig("V", $pyProxy, $str, $str, $objArr)); + makeSig("V", $pyProxy, $str, $str, $objArr), false); code.visitInsn(RETURN); } diff --git a/src/org/python/compiler/ProxyMaker.java b/src/org/python/compiler/ProxyMaker.java --- a/src/org/python/compiler/ProxyMaker.java +++ b/src/org/python/compiler/ProxyMaker.java @@ -729,7 +729,7 @@ protected void callInitProxy(Class[] parameters, Code code) throws Exception { code.visitVarInsn(ALOAD, 0); getArgs(code, parameters); - code.visitMethodInsn(INVOKEVIRTUAL, classfile.name, "__initProxy__", makeSig("V", $objArr)); + code.visitMethodInsn(INVOKEVIRTUAL, classfile.name, "__initProxy__", makeSig("V", $objArr), false); code.visitInsn(RETURN); } diff --git a/src/org/python/core/AnnotationReader.java b/src/org/python/core/AnnotationReader.java --- a/src/org/python/core/AnnotationReader.java +++ b/src/org/python/core/AnnotationReader.java @@ -5,6 +5,7 @@ package org.python.core; import java.io.IOException; +import java.io.InputStream; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassReader; @@ -35,25 +36,23 @@ * @throws IOException - if the classfile is malformed. */ public AnnotationReader(byte[] data) throws IOException { - super(Opcodes.ASM4); + super(Opcodes.ASM5); ClassReader r; try { r = new ClassReader(data); } catch (ArrayIndexOutOfBoundsException e) { - IOException ioe = new IOException("Malformed bytecode: not enough data"); - ioe.initCause(e);// IOException didn't grow a constructor that could take a cause till - // 1.6, so do it the old fashioned way + IOException ioe = new IOException("Malformed bytecode: not enough data", e); throw ioe; } r.accept(this, 0); } - + @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { nextVisitIsVersion = desc.equals("Lorg/python/compiler/APIVersion;"); nextVisitIsMTime = desc.equals("Lorg/python/compiler/MTime;"); nextVisitIsFilename = desc.equals("Lorg/python/compiler/Filename;"); - return new AnnotationVisitor(Opcodes.ASM4) { + return new AnnotationVisitor(Opcodes.ASM5) { public void visit(String name, Object value) { if (nextVisitIsVersion) { diff --git a/src/org/python/core/imp.java b/src/org/python/core/imp.java --- a/src/org/python/core/imp.java +++ b/src/org/python/core/imp.java @@ -27,7 +27,7 @@ private static final String UNKNOWN_SOURCEFILE = ""; - private static final int APIVersion = 35; + private static final int APIVersion = 36; public static final int NO_MTIME = -1; diff --git a/src/org/python/core/packagecache/PackageManager.java b/src/org/python/core/packagecache/PackageManager.java --- a/src/org/python/core/packagecache/PackageManager.java +++ b/src/org/python/core/packagecache/PackageManager.java @@ -3,13 +3,18 @@ package org.python.core.packagecache; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; import org.python.core.Py; import org.python.core.PyJavaPackage; import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyStringMap; +import org.python.core.util.FileUtil; -import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; /** * Abstract package manager. @@ -164,73 +169,40 @@ return p; } + + private static class AccessVisitor extends ClassVisitor { + + private int class_access; + + public AccessVisitor() throws IOException { + super(Opcodes.ASM5); + } + + @Override + public void visit(int version, int access, String name, + String signature, String superName, String[] interfaces) { + class_access = access; + } + + public int getClassAccess() { + return class_access; + } + } + /** * Check that a given stream is a valid Java .class file. And return its * access permissions as an int. */ static protected int checkAccess(java.io.InputStream cstream) - throws java.io.IOException { - java.io.DataInputStream istream = new java.io.DataInputStream(cstream); - + throws IOException { try { - int magic = istream.readInt(); - if (magic != 0xcafebabe) { - return -1; - } - } catch (EOFException eof) { - //Empty or 1 byte file. + ClassReader reader = new ClassReader(cstream); + AccessVisitor visitor = new AccessVisitor(); + reader.accept(visitor, 0); + return visitor.getClassAccess(); + } catch (RuntimeException e) { return -1; } - //int minor = - istream.readShort(); - //int major = - istream.readShort(); - - // Check versions??? - // System.out.println("magic: "+magic+", "+major+", "+minor); - int nconstants = istream.readShort(); - for (int i = 1; i < nconstants; i++) { - int cid = istream.readByte(); - // System.out.println(""+i+" : "+cid); - switch (cid) { - case 7: - istream.skipBytes(2); - break; - case 9: - case 10: - case 11: - istream.skipBytes(4); - break; - case 8: - istream.skipBytes(2); - break; - case 3: - case 4: - istream.skipBytes(4); - break; - case 5: - case 6: - istream.skipBytes(8); - i++; - break; - case 12: - istream.skipBytes(4); - break; - case 1: - // System.out.println("utf: "+istream.readUTF()+";"); - int slength = istream.readUnsignedShort(); - istream.skipBytes(slength); - break; - default: - // System.err.println("unexpected cid: "+cid+", "+i+", "+ - // nconstants); - // for (int j=0; j<10; j++) - // System.err.print(", "+istream.readByte()); - // System.err.println(); - return -1; - } - } - return istream.readShort(); } } diff --git a/src/org/python/expose/generate/ExposedFieldFinder.java b/src/org/python/expose/generate/ExposedFieldFinder.java --- a/src/org/python/expose/generate/ExposedFieldFinder.java +++ b/src/org/python/expose/generate/ExposedFieldFinder.java @@ -14,7 +14,7 @@ private String doc; public ExposedFieldFinder(String name, FieldVisitor delegate) { - super(Opcodes.ASM4); + super(Opcodes.ASM5); fieldName = name; this.delegate = delegate; } diff --git a/src/org/python/expose/generate/ExposedMethodFinder.java b/src/org/python/expose/generate/ExposedMethodFinder.java --- a/src/org/python/expose/generate/ExposedMethodFinder.java +++ b/src/org/python/expose/generate/ExposedMethodFinder.java @@ -35,7 +35,7 @@ String desc, String[] exceptions, MethodVisitor delegate) { - super(Opcodes.ASM4, delegate); + super(Opcodes.ASM5, delegate); this.typeName = typeName; this.onType = onType; this.access = access; diff --git a/src/org/python/expose/generate/ExposedTypeProcessor.java b/src/org/python/expose/generate/ExposedTypeProcessor.java --- a/src/org/python/expose/generate/ExposedTypeProcessor.java +++ b/src/org/python/expose/generate/ExposedTypeProcessor.java @@ -114,7 +114,7 @@ private boolean generatedStaticBlock; private TypeProcessor(ClassVisitor cv) { - super(Opcodes.ASM4, cv); + super(Opcodes.ASM5, cv); } @Override @@ -194,11 +194,14 @@ .replace('.', '/')); mv.visitTypeInsn(NEW, typeExposerType.getInternalName()); mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, typeExposerType.getInternalName(), "", "()V"); - mv.visitMethodInsn(INVOKESTATIC, - PYTYPE.getInternalName(), - "addBuilder", - Type.getMethodDescriptor(VOID, new Type[] {CLASS, TYPEBUILDER})); + mv.visitMethodInsn( + INVOKESPECIAL, typeExposerType.getInternalName(), "", "()V", false); + mv.visitMethodInsn( + INVOKESTATIC, + PYTYPE.getInternalName(), + "addBuilder", + Type.getMethodDescriptor(VOID, new Type[]{CLASS, TYPEBUILDER}), + false); } /** Adds an inner class reference to inner from the class being visited. */ @@ -225,7 +228,7 @@ desc, signature, exceptions); - return new MethodVisitor(Opcodes.ASM4, passthroughVisitor) { + return new MethodVisitor(Opcodes.ASM5, passthroughVisitor) { @Override public void visitCode() { diff --git a/src/org/python/expose/generate/Exposer.java b/src/org/python/expose/generate/Exposer.java --- a/src/org/python/expose/generate/Exposer.java +++ b/src/org/python/expose/generate/Exposer.java @@ -160,7 +160,7 @@ mv.visitMethodInsn(INVOKESPECIAL, onType.getInternalName(), "", - methodDesc(VOID, args)); + methodDesc(VOID, args), false); } /** Calls the method on onType with the given return type and argument types. */ @@ -168,7 +168,7 @@ mv.visitMethodInsn(INVOKEVIRTUAL, onType.getInternalName(), methodName, - methodDesc(returnType, args)); + methodDesc(returnType, args), false); } /** Calls the static method on onType with the given return type and argument types. */ @@ -176,7 +176,7 @@ mv.visitMethodInsn(INVOKESTATIC, onType.getInternalName(), methodName, - methodDesc(returnType, args)); + methodDesc(returnType, args), false); } /** Produces a method descriptor with ret as its return type that takes args. */ diff --git a/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java b/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java --- a/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java +++ b/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java @@ -10,7 +10,7 @@ public class RestrictiveAnnotationVisitor extends AnnotationVisitor { public RestrictiveAnnotationVisitor() { - super(Opcodes.ASM4); + super(Opcodes.ASM5); } public AnnotationVisitor visitAnnotation(String name, String desc) { -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 5 19:36:23 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 05 Jan 2015 18:36:23 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_NPE_in_importing_packag?= =?utf-8?q?es_with_zipped_eggs?= Message-ID: <20150105183609.125880.2089@psf.io> https://hg.python.org/jython/rev/a38c72a35c01 changeset: 7501:a38c72a35c01 user: Jim Baker date: Mon Jan 05 11:36:05 2015 -0700 summary: Fix NPE in importing packages with zipped eggs imp#readCode now uses the more full-featured imp#readCodeData, but it wasn't passing nulls through per its original contract. Fix so we can support zipped eggs again. files: src/org/python/core/imp.java | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/src/org/python/core/imp.java b/src/org/python/core/imp.java --- a/src/org/python/core/imp.java +++ b/src/org/python/core/imp.java @@ -241,7 +241,12 @@ } public static byte[] readCode(String name, InputStream fp, boolean testing, long mtime) throws IOException { - return readCodeData(name, fp, testing, mtime).getBytes(); + CodeData data = readCodeData(name, fp, testing, mtime); + if (data == null) { + return null; + } else { + return data.getBytes(); + } } public static CodeData readCodeData(String name, InputStream fp, boolean testing) throws IOException { -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 04:16:19 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Tue, 06 Jan 2015 03:16:19 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_versions_for_beta4_r?= =?utf-8?q?elease=2E?= Message-ID: <20150106031616.8765.15042@psf.io> https://hg.python.org/jython/rev/6e650bf6302f changeset: 7502:6e650bf6302f user: Frank Wierzbicki date: Tue Jan 06 03:16:19 2015 +0000 summary: Update versions for beta4 release. files: README.txt | 11 +++++------ build.xml | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -1,13 +1,12 @@ -Welcome to Jython 2.7b3 +Welcome to Jython 2.7b4 ======================= -This is the third beta release of the 2.7 version of Jython. Thanks to -Rackspace (http://www.rackspace.com/) for sponsoring this release. +This is the fourth beta release of the 2.7 version of Jython. Thanks to +Amobee (http://www.amobee.com/) for sponsoring this release. Thanks to all who contribute to Jython. -Jython 2.7b3 includes a total rework of ssl which will soon allow pip to work -on Jython (once pip gets a bugfix as well). It also fixes many bugs including -some in binascii support, ast support, and many others. +Jython 2.7b4 includes many bug fixes and code stabilization in prep for +release candidates. As a beta release we are concentrating on bug fixing and stabilizion for a production release. diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -84,15 +84,15 @@ - - + + - + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 04:17:17 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Tue, 06 Jan 2015 03:17:17 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7b4_for_chan?= =?utf-8?q?geset_6e650bf6302f?= Message-ID: <20150106031714.72561.51574@psf.io> https://hg.python.org/jython/rev/e12953dc5e40 changeset: 7503:e12953dc5e40 user: Frank Wierzbicki date: Tue Jan 06 03:17:15 2015 +0000 summary: Added tag v2.7b4 for changeset 6e650bf6302f files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -81,3 +81,4 @@ 5e7462875b633e4f13b77985a1ed5186a0b92cac v2.7b3 5e7462875b633e4f13b77985a1ed5186a0b92cac v2.7b3 744d673392b4bef667ed7d923e0a6c5abeec5d8a v2.7b3 +6e650bf6302fbc142e9fa0397ac2e8f342e16aaf v2.7b4 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 20:22:59 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 06 Jan 2015 19:22:59 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Remove_a_skip_for_test_of_a?= =?utf-8?b?YnMoY29tcGxleCku?= Message-ID: <20150106192259.22395.59785@psf.io> https://hg.python.org/jython/rev/68abf42ab9d7 changeset: 7507:68abf42ab9d7 user: Jeff Allen date: Sun Jan 04 17:43:01 2015 +0000 summary: Remove a skip for test of abs(complex). Missed this one when complex.__abs__ was made conformant. files: Lib/test/test_cmath.py | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -446,11 +446,8 @@ self.assertTrue(math.isnan(abs(complex(2.3, NAN)))) self.assertEqual(abs(complex(INF, NAN)), INF) self.assertTrue(math.isnan(abs(complex(NAN, NAN)))) - if is_jython: - self.assertEqual(abs(complex(1.4e308, 1.4e308)), INF) - else: - if float.__getformat__("double").startswith("IEEE"): - self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308)) + if float.__getformat__("double").startswith("IEEE"): + self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308)) def assertCEqual(self, a, b): eps = 1E-7 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 20:22:59 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 06 Jan 2015 19:22:59 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_skip_for_spurious_faili?= =?utf-8?q?ng_test_in_test=5Fmath=2E?= Message-ID: <20150106192259.8747.50000@psf.io> https://hg.python.org/jython/rev/50f75e697bf0 changeset: 7508:50f75e697bf0 user: Jeff Allen date: Mon Jan 05 15:54:24 2015 +0000 summary: Add skip for spurious failing test in test_math. test_files fails now we have beefed up the test cases, but only because it effectively requires bit-perfect answers for large numbers. Our replacement in test_math_jy is a sufficient test. files: Lib/test/test_math.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1,7 +1,7 @@ # Python test set -- math module # XXXX Should not do tests around zero only -from test.test_support import run_unittest, verbose +from test.test_support import run_unittest, verbose, is_jython import unittest import math import os @@ -933,6 +933,7 @@ else: self.fail("sqrt(-1) didn't raise ValueError") + @unittest.skipIf(is_jython, "superseded in test_math_jy (don't fix me)") @requires_IEEE_754 def test_testfile(self): for id, fn, ar, ai, er, ei, flags in parse_testfile(test_file): -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 20:22:59 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 06 Jan 2015 19:22:59 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Rigorous_tests_for_math=2C_?= =?utf-8?q?and_passing_sinh=2C_cosh=2C_tanh=2E?= Message-ID: <20150106192259.11585.80341@psf.io> https://hg.python.org/jython/rev/7402bd620d52 changeset: 7506:7402bd620d52 user: Jeff Allen date: Sun Jan 04 15:42:03 2015 +0000 summary: Rigorous tests for math, and passing sinh, cosh, tanh. It turns out that Java provides satisfactory implementations of sinh, cosh, and tanh and we don't kneed our own. Defined expectations for accuracy match those in the java.Math javadoc, but in practice 1.7u60 passed at 1 ulp. files: Lib/test/test_math_jy.py | 103 +++++++++++++++++- Misc/make_cmath_testcases.py | 4 +- src/org/python/modules/math.java | 30 +---- 3 files changed, 100 insertions(+), 37 deletions(-) diff --git a/Lib/test/test_math_jy.py b/Lib/test/test_math_jy.py --- a/Lib/test/test_math_jy.py +++ b/Lib/test/test_math_jy.py @@ -5,12 +5,23 @@ import math import unittest from test import test_support +from test.test_math import (MathTests, ulps_check, + parse_testfile, test_file) + from java.lang import Math inf = float('inf') ninf = float('-inf') nan = float('nan') +# Optional tests use mpmath +try: + import mpmath + HAVE_MPMATH = True +except: + HAVE_MPMATH = False + + class MathTestCase(unittest.TestCase): def test_frexp(self): @@ -40,28 +51,104 @@ self.assertRaises(ValueError, math.log, -1.5) self.assertRaises(ValueError, math.log, -0.5) -from test.test_math import MathTests class MathAccuracy(MathTests): # Run the CPython tests but expect accurate results - def ftest(self, name, value, expected): + def ftest(self, name, value, expected, ulps_err=1): + if expected != 0. : # Tolerate small deviation in proportion to expected - tol = Math.ulp(expected) + ulp_unit = Math.ulp(expected) else : # On zero, allow 2**-52. Maybe allow different slack based on name - tol = Math.ulp(1.) + ulp_unit = Math.ulp(1.) - if abs(value-expected) > tol: + # Complex expressions accumulate errors + if name in ('cosh(2)-2*cosh(1)**2', 'sinh(1)**2-cosh(1)**2') : + # ... quite steeply in these cases + ulps_err *= 5 + + err = value-expected + + if abs(err) > ulps_err * ulp_unit: # Use %r to display full precision. - message = '%s returned %r, expected %r' % (name, value, expected) + message = '%s returned %r, expected %r (%r ulps)' % \ + (name, value, expected, round(err/ulp_unit, 1)) self.fail(message) def testConstants(self): - self.ftest('pi', math.pi, Math.PI) # 3.141592653589793238462643 - self.ftest('e', math.e, Math.E) # 2.718281828459045235360287 + # Override MathTests.testConstants requiring equality with java.Math + self.assertEqual(math.pi, Math.PI) + self.assertEqual(math.e, Math.E) + def test_testfile(self, math_module=math, ulps_err=None): + # Rigorous variant of MathTests.test_testfile requiring accuracy in ulps. + fail_fmt = "{}:{}({!r}): expected {!r}, got {!r}" + failures = [] + + for id, fn, ar, ai, er, ei, flags in parse_testfile(test_file): + # Skip if either the input or result is complex, or if + # flags is nonempty + if ai != 0. or ei != 0. or flags: + continue + if fn in ['rect', 'polar']: + # no real versions of rect, polar + continue + + if ulps_err is not None : + fn_ulps_err = ulps_err + else : + # java.Math mostly promises 1 ulp, except for: + if fn in ['atan2'] : + fn_ulps_err = 2 + elif fn in ['cosh', 'sinh', 'tanh'] : + fn_ulps_err = 2.5 + else : + fn_ulps_err = 1 + + func = getattr(math_module, fn) + arg = ar + expected = er + + if 'invalid' in flags or 'divide-by-zero' in flags: + expected = 'ValueError' + elif 'overflow' in flags: + expected = 'OverflowError' + + try: + got = float(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 + accuracy_failure = ulps_check(expected, got, fn_ulps_err) + 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) + + if failures: + self.fail('Failures in test_testfile:\n ' + + '\n '.join(failures)) + + @unittest.skipUnless(HAVE_MPMATH, "requires mpmath module") + def test_testfile_mpmath(self): + # Run the mpmath module on the same material: consistency check during development. + with mpmath.workprec(100) : + self.test_testfile(mpmath, 1, 1) def test_main(): diff --git a/Misc/make_cmath_testcases.py b/Misc/make_cmath_testcases.py --- a/Misc/make_cmath_testcases.py +++ b/Misc/make_cmath_testcases.py @@ -1,5 +1,5 @@ # This work is based on test_math.py in the Python test set. -# It a provides a tool to generate additional +# It a provides a tool to generate additional real test cases. import math import mpmath @@ -116,7 +116,7 @@ def test_main(): with mpmath.workprec(100): generate_cases() - + if __name__ == '__main__': test_main() diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java --- a/src/org/python/modules/math.java +++ b/src/org/python/modules/math.java @@ -197,13 +197,7 @@ } public static double cosh(double v) { - if (isinf(v)) { - return INF; - } - if (isnan(v)) { - return v; - } - return HALF * (Math.exp(v) + Math.exp(-v)); + return Math.cosh(v); } public static double exp(double v) { @@ -366,29 +360,11 @@ } public static double sinh(double v) { - if (isnan(v)) { - return v; - } - if (isinf(v)) { - return v; - } - return HALF * (Math.exp(v) - Math.exp(-v)); + return Math.sinh(v); } public static double tanh(double v) { - if (isnan(v)) { - return v; - } - if (isinf(v)) { - if (isninf(v)) { - return MINUS_ONE; - } - return ONE; - } - if (v == MINUS_ZERO) { - return v; - } - return sinh(v) / cosh(v); + return Math.tanh(v); } public static double fabs(double v) { -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 20:22:59 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 06 Jan 2015 19:22:59 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_real-line_test_cases_to?= =?utf-8?q?_Lib/test/cmath=5Ftestcases=2E?= Message-ID: <20150106192258.11563.11335@psf.io> https://hg.python.org/jython/rev/ec0ea6dd75b8 changeset: 7505:ec0ea6dd75b8 user: Jeff Allen date: Sun Jan 04 00:16:10 2015 +0000 summary: Add real-line test cases to Lib/test/cmath_testcases. Adds a tool in Misc to generate additional test cases to be used in test_math (real argument, real result), and adds these cases to cmath_testcases.txt . There may be test failures in test_math_jy as latent defects in math.java are revealed. files: Lib/test/cmath_testcases.txt | 137 +++++++++++++++++++++++ Misc/make_cmath_testcases.py | 124 ++++++++++++++++++++ 2 files changed, 261 insertions(+), 0 deletions(-) diff --git a/Lib/test/cmath_testcases.txt b/Lib/test/cmath_testcases.txt --- a/Lib/test/cmath_testcases.txt +++ b/Lib/test/cmath_testcases.txt @@ -53,6 +53,12 @@ -- MPFR homepage at http://www.mpfr.org for more information about the -- MPFR project. +-- A minority of the test cases were generated with the help of +-- mpmath 0.19 at 100 bit accuracy (http://mpmath.org) to provide +-- coverage of real functions with real-valued arguments. These are +-- used particularly in test.test_math.MathTests.test_testfile. +-- These additions were made originally for the Jython project. + -------------------------- -- acos: Inverse cosine -- @@ -847,6 +853,18 @@ atan0303 atan -1e-165 1.0 -> -0.78539816339744828 190.30984376228875 atan0304 atan -9.9998886718268301e-321 -1.0 -> -0.78539816339744828 -368.76019403576692 +-- Additional real values (Jython) +atan0400 atan 1.7976931348623157e+308 0.0 -> 1.5707963267948966192 0.0 +atan0401 atan -1.7976931348623157e+308 0.0 -> -1.5707963267948966192 0.0 +atan0402 atan 1e-17 0.0 -> 1.0000000000000000715e-17 0.0 +atan0403 atan -1e-17 0.0 -> -1.0000000000000000715e-17 0.0 +atan0404 atan 0.0001 0.0 -> 0.000099999999666666673459 0.0 +atan0405 atan -0.0001 0.0 -> -0.000099999999666666673459 0.0 +atan0406 atan 0.999999999999999 0.0 -> 0.78539816339744781002 0.0 +atan0407 atan 1.000000000000001 0.0 -> 0.78539816339744886473 0.0 +atan0408 atan 14.101419947171719 0.0 -> 1.4999999999999999969 0.0 +atan0409 atan 1255.7655915007897 0.0 -> 1.5700000000000000622 0.0 + -- special values atan1000 atan -0.0 0.0 -> -0.0 0.0 atan1001 atan nan 0.0 -> nan 0.0 @@ -1512,6 +1530,11 @@ sqrt0140 sqrt 1.6999999999999999e+308 -1.6999999999999999e+308 -> 1.4325088230154573e+154 -5.9336458271212207e+153 sqrt0141 sqrt -1.797e+308 -9.9999999999999999e+306 -> 3.7284476432057307e+152 -1.3410406899802901e+154 +-- Additional real values (Jython) +sqrt0150 sqrt 1.7976931348623157e+308 0.0 -> 1.3407807929942596355e+154 0.0 +sqrt0151 sqrt 2.2250738585072014e-308 0.0 -> 1.4916681462400413487e-154 0.0 +sqrt0152 sqrt 5e-324 0.0 -> 2.2227587494850774834e-162 0.0 + -- special values sqrt1000 sqrt 0.0 0.0 -> 0.0 0.0 sqrt1001 sqrt -0.0 0.0 -> 0.0 0.0 @@ -1614,6 +1637,20 @@ exp0053 exp 710.0 1.6 -> -6.5231579995501372e+306 inf overflow exp0054 exp 710.0 2.8 -> -inf 7.4836177417448528e+307 overflow +-- Additional real values (Jython) +exp0070 exp 1e-08 0.0 -> 1.00000001000000005 0.0 +exp0071 exp 0.0003 0.0 -> 1.0003000450045003375 0.0 +exp0072 exp 0.2 0.0 -> 1.2214027581601698475 0.0 +exp0073 exp 1.0 0.0 -> 2.7182818284590452354 0.0 +exp0074 exp -1e-08 0.0 -> 0.99999999000000005 0.0 +exp0075 exp -0.0003 0.0 -> 0.99970004499550033751 0.0 +exp0076 exp -1.0 0.0 -> 0.3678794411714423216 0.0 +exp0077 exp 2.220446049250313e-16 0.0 -> 1.000000000000000222 0.0 +exp0078 exp -1.1102230246251565e-16 0.0 -> 0.99999999999999988898 0.0 +exp0079 exp 2.302585092994046 0.0 -> 10.000000000000002171 0.0 +exp0080 exp -2.302585092994046 0.0 -> 0.099999999999999978292 0.0 +exp0081 exp 709.7827 0.0 -> 1.7976699566638014654e+308 0.0 + -- special values exp1000 exp 0.0 0.0 -> 1.0 0.0 exp1001 exp -0.0 0.0 -> 1.0 0.0 @@ -1706,6 +1743,23 @@ cosh0030 cosh 710.5 2.3519999999999999 -> -1.2967465239355998e+308 1.3076707908857333e+308 cosh0031 cosh -710.5 0.69999999999999996 -> 1.4085466381392499e+308 -1.1864024666450239e+308 +-- Additional real values (Jython) +cosh0050 cosh 1e-150 0.0 -> 1.0 0.0 +cosh0051 cosh 1e-18 0.0 -> 1.0 0.0 +cosh0052 cosh 1e-09 0.0 -> 1.0000000000000000005 0.0 +cosh0053 cosh 0.0003 0.0 -> 1.0000000450000003375 0.0 +cosh0054 cosh 0.2 0.0 -> 1.0200667556190758485 0.0 +cosh0055 cosh 1.0 0.0 -> 1.5430806348152437785 0.0 +cosh0056 cosh -1e-18 0.0 -> 1.0 0.0 +cosh0057 cosh -0.0003 0.0 -> 1.0000000450000003375 0.0 +cosh0058 cosh -1.0 0.0 -> 1.5430806348152437785 0.0 +cosh0059 cosh 1.3169578969248168 0.0 -> 2.0000000000000001504 0.0 +cosh0060 cosh -1.3169578969248168 0.0 -> 2.0000000000000001504 0.0 +cosh0061 cosh 17.328679513998633 0.0 -> 16777216.000000021938 0.0 +cosh0062 cosh 18.714973875118524 0.0 -> 67108864.000000043662 0.0 +cosh0063 cosh 709.7827 0.0 -> 8.9883497833190073272e+307 0.0 +cosh0064 cosh -709.7827 0.0 -> 8.9883497833190073272e+307 0.0 + -- special values cosh1000 cosh 0.0 0.0 -> 1.0 0.0 cosh1001 cosh 0.0 inf -> nan 0.0 invalid ignore-imag-sign @@ -1798,6 +1852,24 @@ sinh0030 sinh 710.5 -2.3999999999999999 -> -1.3579970564885919e+308 -1.24394470907798e+308 sinh0031 sinh -710.5 0.80000000000000004 -> -1.2830671601735164e+308 1.3210954193997678e+308 +-- Additional real values (Jython) +sinh0050 sinh 1e-100 0.0 -> 1.00000000000000002e-100 0.0 +sinh0051 sinh 5e-17 0.0 -> 4.9999999999999998955e-17 0.0 +sinh0052 sinh 1e-16 0.0 -> 9.999999999999999791e-17 0.0 +sinh0053 sinh 3.7e-08 0.0 -> 3.7000000000000008885e-8 0.0 +sinh0054 sinh 0.001 0.0 -> 0.0010000001666666750208 0.0 +sinh0055 sinh 0.2 0.0 -> 0.20133600254109399895 0.0 +sinh0056 sinh 1.0 0.0 -> 1.1752011936438014569 0.0 +sinh0057 sinh -3.7e-08 0.0 -> -3.7000000000000008885e-8 0.0 +sinh0058 sinh -0.001 0.0 -> -0.0010000001666666750208 0.0 +sinh0059 sinh -1.0 0.0 -> -1.1752011936438014569 0.0 +sinh0060 sinh 1.4436354751788103 0.0 -> 1.9999999999999999078 0.0 +sinh0061 sinh -1.4436354751788103 0.0 -> -1.9999999999999999078 0.0 +sinh0062 sinh 17.328679513998633 0.0 -> 16777215.999999992136 0.0 +sinh0063 sinh 18.714973875118524 0.0 -> 67108864.000000036211 0.0 +sinh0064 sinh 709.7827 0.0 -> 8.9883497833190073272e+307 0.0 +sinh0065 sinh -709.7827 0.0 -> -8.9883497833190073272e+307 0.0 + -- special values sinh1000 sinh 0.0 0.0 -> 0.0 0.0 sinh1001 sinh 0.0 inf -> 0.0 nan invalid ignore-real-sign @@ -1892,6 +1964,24 @@ tanh0032 tanh 1000 -2.3199999999999998 -> 1.0 0.0 tanh0033 tanh -1.0000000000000001e+300 -9.6699999999999999 -> -1.0 -0.0 +-- Additional real values (Jython) +tanh0050 tanh 1e-100 0.0 -> 1.00000000000000002e-100 0.0 +tanh0051 tanh 5e-17 0.0 -> 4.9999999999999998955e-17 0.0 +tanh0052 tanh 1e-16 0.0 -> 9.999999999999999791e-17 0.0 +tanh0053 tanh 3.7e-08 0.0 -> 3.6999999999999983559e-8 0.0 +tanh0054 tanh 0.001 0.0 -> 0.00099999966666680002076 0.0 +tanh0055 tanh 0.2 0.0 -> 0.19737532022490401141 0.0 +tanh0056 tanh 1.0 0.0 -> 0.76159415595576488812 0.0 +tanh0057 tanh -3.7e-08 0.0 -> -3.6999999999999983559e-8 0.0 +tanh0058 tanh -0.001 0.0 -> -0.00099999966666680002076 0.0 +tanh0059 tanh -1.0 0.0 -> -0.76159415595576488812 0.0 +tanh0060 tanh 0.5493061443340549 0.0 -> 0.50000000000000003402 0.0 +tanh0061 tanh -0.5493061443340549 0.0 -> -0.50000000000000003402 0.0 +tanh0062 tanh 17.328679513998633 0.0 -> 0.99999999999999822364 0.0 +tanh0063 tanh 18.714973875118524 0.0 -> 0.99999999999999988898 0.0 +tanh0064 tanh 711 0.0 -> 1.0 0.0 +tanh0065 tanh 1.797e+308 0.0 -> 1.0 0.0 + --special values tanh1000 tanh 0.0 0.0 -> 0.0 0.0 tanh1001 tanh 0.0 inf -> nan nan invalid @@ -1980,6 +2070,22 @@ cos0022 cos 7.9914515433858515 0.71659966615501436 -> -0.17375439906936566 -0.77217043527294582 cos0023 cos 0.45124351152540226 1.6992693993812158 -> 2.543477948972237 -1.1528193694875477 +-- Additional real values (Jython) +cos0050 cos 1e-150 0.0 -> 1.0 0.0 +cos0051 cos 1e-18 0.0 -> 1.0 0.0 +cos0052 cos 1e-09 0.0 -> 0.9999999999999999995 0.0 +cos0053 cos 0.0003 0.0 -> 0.9999999550000003375 0.0 +cos0054 cos 0.2 0.0 -> 0.98006657784124162892 0.0 +cos0055 cos 1.0 0.0 -> 0.5403023058681397174 0.0 +cos0056 cos -1e-18 0.0 -> 1.0 0.0 +cos0057 cos -0.0003 0.0 -> 0.9999999550000003375 0.0 +cos0058 cos -1.0 0.0 -> 0.5403023058681397174 0.0 +cos0059 cos 1.0471975511965976 0.0 -> 0.50000000000000009945 0.0 +cos0060 cos 2.5707963267948966 0.0 -> -0.84147098480789647357 0.0 +cos0061 cos -2.5707963267948966 0.0 -> -0.84147098480789647357 0.0 +cos0062 cos 18 0.0 -> 0.66031670824408014482 0.0 +cos0063 cos 18.0 0.0 -> 0.66031670824408014482 0.0 + -- special values cos1000 cos -0.0 0.0 -> 1.0 0.0 cos1001 cos -inf 0.0 -> nan 0.0 invalid ignore-imag-sign @@ -2068,6 +2174,20 @@ sin0022 sin 1.1518087354403725 4.8597235966150558 -> 58.919141989603041 26.237003403758852 sin0023 sin 0.00087773078406649192 34.792379211312095 -> 565548145569.38245 644329685822700.62 +-- Additional real values (Jython) +sin0050 sin 1e-100 0.0 -> 1.00000000000000002e-100 0.0 +sin0051 sin 3.7e-08 0.0 -> 3.6999999999999992001e-8 0.0 +sin0052 sin 0.001 0.0 -> 0.00099999983333334168748 0.0 +sin0053 sin 0.2 0.0 -> 0.19866933079506122634 0.0 +sin0054 sin 1.0 0.0 -> 0.84147098480789650665 0.0 +sin0055 sin -3.7e-08 0.0 -> -3.6999999999999992001e-8 0.0 +sin0056 sin -0.001 0.0 -> -0.00099999983333334168748 0.0 +sin0057 sin -1.0 0.0 -> -0.84147098480789650665 0.0 +sin0058 sin 0.5235987755982989 0.0 -> 0.50000000000000004642 0.0 +sin0059 sin -0.5235987755982989 0.0 -> -0.50000000000000004642 0.0 +sin0060 sin 2.6179938779914944 0.0 -> 0.49999999999999996018 0.0 +sin0061 sin -2.6179938779914944 0.0 -> -0.49999999999999996018 0.0 + -- special values sin1000 sin -0.0 0.0 -> -0.0 0.0 sin1001 sin -inf 0.0 -> nan 0.0 invalid ignore-imag-sign @@ -2156,6 +2276,23 @@ tan0022 tan 1.1615313900880577 1.7956298728647107 -> 0.041793186826390362 1.0375339546034792 tan0023 tan 0.067014779477908945 5.8517361577457097 -> 2.2088639754800034e-06 0.9999836182420061 +-- Additional real values (Jython) +tan0050 tan 1e-100 0.0 -> 1.00000000000000002e-100 0.0 +tan0051 tan 3.7e-08 0.0 -> 3.7000000000000017328e-8 0.0 +tan0052 tan 0.001 0.0 -> 0.0010000003333334666875 0.0 +tan0053 tan 0.2 0.0 -> 0.20271003550867249488 0.0 +tan0054 tan 1.0 0.0 -> 1.5574077246549022305 0.0 +tan0055 tan -3.7e-08 0.0 -> -3.7000000000000017328e-8 0.0 +tan0056 tan -0.001 0.0 -> -0.0010000003333334666875 0.0 +tan0057 tan -1.0 0.0 -> -1.5574077246549022305 0.0 +tan0058 tan 0.4636476090008061 0.0 -> 0.49999999999999997163 0.0 +tan0059 tan -0.4636476090008061 0.0 -> -0.49999999999999997163 0.0 +tan0060 tan 1.1071487177940904 0.0 -> 1.9999999999999995298 0.0 +tan0061 tan -1.1071487177940904 0.0 -> -1.9999999999999995298 0.0 +tan0062 tan 1.5 0.0 -> 14.101419947171719388 0.0 +tan0063 tan 1.57 0.0 -> 1255.7655915007896475 0.0 +tan0064 tan 1.5707963267948961 0.0 -> 1978937966095219.0538 0.0 + -- special values tan1000 tan -0.0 0.0 -> -0.0 0.0 tan1001 tan -inf 0.0 -> nan nan invalid diff --git a/Misc/make_cmath_testcases.py b/Misc/make_cmath_testcases.py new file mode 100644 --- /dev/null +++ b/Misc/make_cmath_testcases.py @@ -0,0 +1,124 @@ +# This work is based on test_math.py in the Python test set. +# It a provides a tool to generate additional + +import math +import mpmath + + +# Table of additional real test cases. The layout is +# +# function : ( starting_number [ x1, x2, x3, ... ] ), +# +# Where tests will be numbered functionNNNN and each xn +# generates a new test with (complex) argument xn + 0j. + +cases_to_generate = { + + 'atan' : ( 400, [ + float.fromhex('0x1.fffffffffffffp1023'), + float.fromhex('-0x1.fffffffffffffp1023'), + 1e-17, -1e-17, 1e-4, -1e-4, + 1 - 1e-15, 1 + 1e-15, + 14.101419947171719, # tan(1.5) + 1255.7655915007896, # tan(1.57) + ]), + + 'cos' : ( 50, [ + 1e-150, 1e-18, 1e-9, 0.0003, 0.2, 1.0, + -1e-18, -0.0003, -1.0, + 1.0471975511965977, # -> 0.5 + 2.5707963267948966, + -2.5707963267948966, + 18, 18.0 + ]), + + 'cosh' : ( 50, [ + 1e-150, 1e-18, 1e-9, 0.0003, 0.2, 1.0, + -1e-18, -0.0003, -1.0, + 1.3169578969248167086, # -> 2. + -1.3169578969248167086, + 25*math.log(2), # cosh != exp at 52 bits + 27*math.log(2), # cosh == exp at 52 bits + 709.7827, # not quite overflow + -709.7827, # not quite overflow + ]), + + 'exp' : ( 70, [ + 1e-8, 0.0003, 0.2, 1.0, + -1e-8, -0.0003, -1.0, + 2**-52, -2**-53, # exp != 1 (just) + 2.3025850929940457, # -> 10 + -2.3025850929940457, + 709.7827, # not quite overflow + ]), + + 'sin' : ( 50, [ + 1e-100, 3.7e-8, 0.001, 0.2, 1.0, + -3.7e-8, -0.001, -1.0, + 0.5235987755982989, # -> 0.5 + -0.5235987755982989, + 2.617993877991494365, + -2.617993877991494365, + ]), + + 'sinh' : ( 50, [ + 1e-100, 5e-17, 1e-16, 3.7e-8, 0.001, 0.2, 1.0, + -3.7e-8, -0.001, -1.0, + 1.44363547517881034, # -> 2. + -1.44363547517881034, + 25*math.log(2), # sinh != exp at 52 bits + 27*math.log(2), # sinh == exp at 52 bits + 709.7827, # not quite overflow + -709.7827, # not quite overflow + ]), + + 'tan' : ( 50, [ + 1e-100, 3.7e-8, 0.001, 0.2, 1.0, + -3.7e-8, -0.001, -1.0, + 0.463647609000806116, # -> 0.5 + -0.463647609000806116, + 1.1071487177940905, # -> 0.5 + -1.1071487177940905, + 1.5, + 1.57, + math.pi/2 - 2**-51, + ]), + + 'tanh' : ( 50, [ + 1e-100, 5e-17, 1e-16, 3.7e-8, 0.001, 0.2, 1.0, + -3.7e-8, -0.001, -1.0, + 0.54930614433405484, # -> 0.5 + -0.54930614433405484, + 25*math.log(2), # sinh != cosh at 52 bits + 27*math.log(2), # sinh == cosh at 52 bits + 711, # oveflow cosh in naive impl + 1.797e+308, # risk overflow + ]), + + 'sqrt' : ( 150, [ + float.fromhex('0x1.fffffffffffffp1023'), + float.fromhex('0x1.0p-1022'), + float.fromhex('0x0.0000000000001p-1022'), + ]), + } + +def generate_cases() : + fmt = "{}{:04d} {} {!r} 0.0 -> {} 0.0" + for fn in sorted(cases_to_generate.keys()): + print "-- Additional real values (Jython)" + count, xlist = cases_to_generate[fn] + for x in xlist: + func = getattr(mpmath, fn) + y = func(x) + print fmt.format(fn, count, fn, x, mpmath.nstr(y, 20) ) + count += 1 + +def test_main(): + with mpmath.workprec(100): + generate_cases() + +if __name__ == '__main__': + test_main() + + # Conveniences for interactive use + from mpmath import mp, mpf, workprec, workdps, nstr -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 20:22:59 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 06 Jan 2015 19:22:59 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_our_own_copy_of_Lib/tes?= =?utf-8?q?t/cmath=5Ftestcases=2E?= Message-ID: <20150106192258.8749.32141@psf.io> https://hg.python.org/jython/rev/c86794b9c1fa changeset: 7504:c86794b9c1fa parent: 7490:7bae6be634fb user: Jeff Allen date: Sat Jan 03 23:54:26 2015 +0000 summary: Add our own copy of Lib/test/cmath_testcases. files: Lib/test/cmath_testcases.txt | 2365 ++++++++++++++++++++++ 1 files changed, 2365 insertions(+), 0 deletions(-) diff --git a/Lib/test/cmath_testcases.txt b/Lib/test/cmath_testcases.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cmath_testcases.txt @@ -0,0 +1,2365 @@ +-- Testcases for functions in cmath. +-- +-- Each line takes the form: +-- +-- -> +-- +-- where: +-- +-- is a short name identifying the test, +-- +-- is the function to be tested (exp, cos, asinh, ...), +-- +-- is a pair of floats separated by whitespace +-- representing real and imaginary parts of a complex number, and +-- +-- is the expected (ideal) output value, again +-- represented as a pair of floats. +-- +-- is a list of the floating-point flags required by C99 +-- +-- The possible flags are: +-- +-- divide-by-zero : raised when a finite input gives a +-- mathematically infinite result. +-- +-- overflow : raised when a finite input gives a finite result whose +-- real or imaginary part is too large to fit in the usual range +-- of an IEEE 754 double. +-- +-- invalid : raised for invalid inputs. +-- +-- ignore-real-sign : indicates that the sign of the real part of +-- the result is unspecified; if the real part of the result is +-- given as inf, then both -inf and inf should be accepted as +-- correct. +-- +-- ignore-imag-sign : indicates that the sign of the imaginary part +-- of the result is unspecified. +-- +-- Flags may appear in any order. +-- +-- Lines beginning with '--' (like this one) start a comment, and are +-- ignored. Blank lines, or lines containing only whitespace, are also +-- ignored. + +-- The majority of the values below were computed with the help of +-- version 2.3 of the MPFR library for multiple-precision +-- floating-point computations with correct rounding. All output +-- values in this file are (modulo yet-to-be-discovered bugs) +-- correctly rounded, provided that each input and output decimal +-- floating-point value below is interpreted as a representation of +-- the corresponding nearest IEEE 754 double-precision value. See the +-- MPFR homepage at http://www.mpfr.org for more information about the +-- MPFR project. + + +-------------------------- +-- acos: Inverse cosine -- +-------------------------- + +-- zeros +acos0000 acos 0.0 0.0 -> 1.5707963267948966 -0.0 +acos0001 acos 0.0 -0.0 -> 1.5707963267948966 0.0 +acos0002 acos -0.0 0.0 -> 1.5707963267948966 -0.0 +acos0003 acos -0.0 -0.0 -> 1.5707963267948966 0.0 + +-- branch points: +/-1 +acos0010 acos 1.0 0.0 -> 0.0 -0.0 +acos0011 acos 1.0 -0.0 -> 0.0 0.0 +acos0012 acos -1.0 0.0 -> 3.1415926535897931 -0.0 +acos0013 acos -1.0 -0.0 -> 3.1415926535897931 0.0 + +-- values along both sides of real axis +acos0020 acos -9.8813129168249309e-324 0.0 -> 1.5707963267948966 -0.0 +acos0021 acos -9.8813129168249309e-324 -0.0 -> 1.5707963267948966 0.0 +acos0022 acos -1e-305 0.0 -> 1.5707963267948966 -0.0 +acos0023 acos -1e-305 -0.0 -> 1.5707963267948966 0.0 +acos0024 acos -1e-150 0.0 -> 1.5707963267948966 -0.0 +acos0025 acos -1e-150 -0.0 -> 1.5707963267948966 0.0 +acos0026 acos -9.9999999999999998e-17 0.0 -> 1.5707963267948968 -0.0 +acos0027 acos -9.9999999999999998e-17 -0.0 -> 1.5707963267948968 0.0 +acos0028 acos -0.001 0.0 -> 1.5717963269615634 -0.0 +acos0029 acos -0.001 -0.0 -> 1.5717963269615634 0.0 +acos0030 acos -0.57899999999999996 0.0 -> 2.1882979816120667 -0.0 +acos0031 acos -0.57899999999999996 -0.0 -> 2.1882979816120667 0.0 +acos0032 acos -0.99999999999999989 0.0 -> 3.1415926386886319 -0.0 +acos0033 acos -0.99999999999999989 -0.0 -> 3.1415926386886319 0.0 +acos0034 acos -1.0000000000000002 0.0 -> 3.1415926535897931 -2.1073424255447014e-08 +acos0035 acos -1.0000000000000002 -0.0 -> 3.1415926535897931 2.1073424255447014e-08 +acos0036 acos -1.0009999999999999 0.0 -> 3.1415926535897931 -0.044717633608306849 +acos0037 acos -1.0009999999999999 -0.0 -> 3.1415926535897931 0.044717633608306849 +acos0038 acos -2.0 0.0 -> 3.1415926535897931 -1.3169578969248168 +acos0039 acos -2.0 -0.0 -> 3.1415926535897931 1.3169578969248168 +acos0040 acos -23.0 0.0 -> 3.1415926535897931 -3.8281684713331012 +acos0041 acos -23.0 -0.0 -> 3.1415926535897931 3.8281684713331012 +acos0042 acos -10000000000000000.0 0.0 -> 3.1415926535897931 -37.534508668464674 +acos0043 acos -10000000000000000.0 -0.0 -> 3.1415926535897931 37.534508668464674 +acos0044 acos -9.9999999999999998e+149 0.0 -> 3.1415926535897931 -346.08091112966679 +acos0045 acos -9.9999999999999998e+149 -0.0 -> 3.1415926535897931 346.08091112966679 +acos0046 acos -1.0000000000000001e+299 0.0 -> 3.1415926535897931 -689.16608998577965 +acos0047 acos -1.0000000000000001e+299 -0.0 -> 3.1415926535897931 689.16608998577965 +acos0048 acos 9.8813129168249309e-324 0.0 -> 1.5707963267948966 -0.0 +acos0049 acos 9.8813129168249309e-324 -0.0 -> 1.5707963267948966 0.0 +acos0050 acos 1e-305 0.0 -> 1.5707963267948966 -0.0 +acos0051 acos 1e-305 -0.0 -> 1.5707963267948966 0.0 +acos0052 acos 1e-150 0.0 -> 1.5707963267948966 -0.0 +acos0053 acos 1e-150 -0.0 -> 1.5707963267948966 0.0 +acos0054 acos 9.9999999999999998e-17 0.0 -> 1.5707963267948966 -0.0 +acos0055 acos 9.9999999999999998e-17 -0.0 -> 1.5707963267948966 0.0 +acos0056 acos 0.001 0.0 -> 1.56979632662823 -0.0 +acos0057 acos 0.001 -0.0 -> 1.56979632662823 0.0 +acos0058 acos 0.57899999999999996 0.0 -> 0.95329467197772655 -0.0 +acos0059 acos 0.57899999999999996 -0.0 -> 0.95329467197772655 0.0 +acos0060 acos 0.99999999999999989 0.0 -> 1.4901161193847656e-08 -0.0 +acos0061 acos 0.99999999999999989 -0.0 -> 1.4901161193847656e-08 0.0 +acos0062 acos 1.0000000000000002 0.0 -> 0.0 -2.1073424255447014e-08 +acos0063 acos 1.0000000000000002 -0.0 -> 0.0 2.1073424255447014e-08 +acos0064 acos 1.0009999999999999 0.0 -> 0.0 -0.044717633608306849 +acos0065 acos 1.0009999999999999 -0.0 -> 0.0 0.044717633608306849 +acos0066 acos 2.0 0.0 -> 0.0 -1.3169578969248168 +acos0067 acos 2.0 -0.0 -> 0.0 1.3169578969248168 +acos0068 acos 23.0 0.0 -> 0.0 -3.8281684713331012 +acos0069 acos 23.0 -0.0 -> 0.0 3.8281684713331012 +acos0070 acos 10000000000000000.0 0.0 -> 0.0 -37.534508668464674 +acos0071 acos 10000000000000000.0 -0.0 -> 0.0 37.534508668464674 +acos0072 acos 9.9999999999999998e+149 0.0 -> 0.0 -346.08091112966679 +acos0073 acos 9.9999999999999998e+149 -0.0 -> 0.0 346.08091112966679 +acos0074 acos 1.0000000000000001e+299 0.0 -> 0.0 -689.16608998577965 +acos0075 acos 1.0000000000000001e+299 -0.0 -> 0.0 689.16608998577965 + +-- random inputs +acos0100 acos -3.3307113324596682 -10.732007530863266 -> 1.8706085694482339 3.113986806554613 +acos0101 acos -2863.952991743291 -2681013315.2571239 -> 1.5707973950301699 22.402607843274758 +acos0102 acos -0.33072639793220088 -0.85055464658253055 -> 1.8219426895922601 0.79250166729311966 +acos0103 acos -2.5722325842097802 -12.703940809821574 -> 1.7699942413107408 3.2565170156527325 +acos0104 acos -42.495233785459583 -0.54039320751337161 -> 3.1288732573153304 4.4424815519735601 +acos0105 acos -1.1363818625856401 9641.1325498630376 -> 1.5709141948820049 -9.8669410553254284 +acos0106 acos -2.4398426824157866e-11 0.33002051890266165 -> 1.570796326818066 -0.32430578041578667 +acos0107 acos -1.3521340428186552 2.9369737912076772 -> 1.9849059192339338 -1.8822893674117942 +acos0108 acos -1.827364706477915 1.0355459232147557 -> 2.5732246307960032 -1.4090688267854969 +acos0109 acos -0.25978373706403546 10.09712669185833 -> 1.5963940386378306 -3.0081673050196063 +acos0110 acos 0.33561778471072551 -4587350.6823999118 -> 1.5707962536333251 16.031960402579539 +acos0111 acos 0.49133444610998445 -0.8071422362990015 -> 1.1908761712801788 0.78573345813187867 +acos0112 acos 0.42196734507823974 -2.4812965431745115 -> 1.414091186100692 1.651707260988172 +acos0113 acos 2.961426210100655 -219.03295695248664 -> 1.5572768319822778 6.0824659885827304 +acos0114 acos 2.886209063652641 -20.38011207220606 -> 1.4302765252297889 3.718201853147642 +acos0115 acos 0.4180568075276509 1.4833433990823484 -> 1.3393834558303042 -1.2079847758301576 +acos0116 acos 52.376111405924718 0.013930429001941001 -> 0.00026601761804024188 -4.6515066691204714 +acos0117 acos 41637948387.625969 1.563418292894041 -> 3.7547918507883548e-11 -25.145424989809381 +acos0118 acos 0.061226659122249526 0.8447234394615154 -> 1.5240280306367315 -0.76791798971140812 +acos0119 acos 2.4480466420442959e+26 0.18002339201384662 -> 7.353756620564798e-28 -61.455650015996376 + +-- values near infinity +acos0200 acos 1.6206860518683021e+308 1.0308426226285283e+308 -> 0.56650826093826223 -710.54206874241561 +acos0201 acos 1.2067735875070062e+308 -1.3429173724390276e+308 -> 0.83874369390864889 710.48017794027498 +acos0202 acos -7.4130145132549047e+307 1.1759130543927645e+308 -> 2.1332729346478536 -710.21871115698752 +acos0203 acos -8.6329426442257249e+307 -1.2316282952184133e+308 -> 2.1821511032444838 710.29752145697148 +acos0204 acos 0.0 1.4289713855849746e+308 -> 1.5707963267948966 -710.24631069738996 +acos0205 acos -0.0 1.3153524545987432e+308 -> 1.5707963267948966 -710.1634604787539 +acos0206 acos 0.0 -9.6229037669269321e+307 -> 1.5707963267948966 709.85091679573691 +acos0207 acos -0.0 -4.9783616421107088e+307 -> 1.5707963267948966 709.19187157911233 +acos0208 acos 1.3937541925739389e+308 0.0 -> 0.0 -710.22135678707264 +acos0209 acos 9.1362388967371536e+307 -0.0 -> 0.0 709.79901953124613 +acos0210 acos -1.3457361220697436e+308 0.0 -> 3.1415926535897931 -710.18629698871848 +acos0211 acos -5.4699090056144284e+307 -0.0 -> 3.1415926535897931 709.28603271085649 +acos0212 acos 1.5880716932358901e+308 5.5638401252339929 -> 3.503519487773873e-308 -710.35187633140583 +acos0213 acos 1.2497211663463164e+308 -3.0456477717911024 -> 2.4370618453197486e-308 710.11227628223412 +acos0214 acos -9.9016224006029528e+307 4.9570427340789056 -> 3.1415926535897931 -709.87946935229468 +acos0215 acos -1.5854071066874139e+308 -4.4233577741497783 -> 3.1415926535897931 710.35019704672004 +acos0216 acos 9.3674623083647628 1.5209559051877979e+308 -> 1.5707963267948966 -710.30869484491086 +acos0217 acos 8.1773832021784383 -6.6093445795000056e+307 -> 1.5707963267948966 709.4752552227792 +acos0218 acos -3.1845935000665104 1.5768856396650893e+308 -> 1.5707963267948966 -710.34480761042687 +acos0219 acos -1.0577303880953903 -6.4574626815735613e+307 -> 1.5707963267948966 709.45200719662046 + +-- values near 0 +acos0220 acos 1.8566986970714045e-320 3.1867234156760402e-321 -> 1.5707963267948966 -3.1867234156760402e-321 +acos0221 acos 7.9050503334599447e-323 -8.8931816251424378e-323 -> 1.5707963267948966 8.8931816251424378e-323 +acos0222 acos -4.4465908125712189e-323 2.4654065097222727e-311 -> 1.5707963267948966 -2.4654065097222727e-311 +acos0223 acos -6.1016916408192619e-311 -2.4703282292062327e-323 -> 1.5707963267948966 2.4703282292062327e-323 +acos0224 acos 0.0 3.4305783621842729e-311 -> 1.5707963267948966 -3.4305783621842729e-311 +acos0225 acos -0.0 1.6117409498633145e-319 -> 1.5707963267948966 -1.6117409498633145e-319 +acos0226 acos 0.0 -4.9900630229965901e-322 -> 1.5707963267948966 4.9900630229965901e-322 +acos0227 acos -0.0 -4.4889279210592818e-311 -> 1.5707963267948966 4.4889279210592818e-311 +acos0228 acos 5.3297678681477214e-312 0.0 -> 1.5707963267948966 -0.0 +acos0229 acos 6.2073425897211614e-313 -0.0 -> 1.5707963267948966 0.0 +acos0230 acos -4.9406564584124654e-324 0.0 -> 1.5707963267948966 -0.0 +acos0231 acos -1.7107517052899003e-318 -0.0 -> 1.5707963267948966 0.0 + +-- special values +acos1000 acos 0.0 0.0 -> 1.5707963267948966 -0.0 +acos1001 acos 0.0 -0.0 -> 1.5707963267948966 0.0 +acos1002 acos -0.0 0.0 -> 1.5707963267948966 -0.0 +acos1003 acos -0.0 -0.0 -> 1.5707963267948966 0.0 +acos1004 acos 0.0 nan -> 1.5707963267948966 nan +acos1005 acos -0.0 nan -> 1.5707963267948966 nan +acos1006 acos -2.3 inf -> 1.5707963267948966 -inf +acos1007 acos -0.0 inf -> 1.5707963267948966 -inf +acos1008 acos 0.0 inf -> 1.5707963267948966 -inf +acos1009 acos 2.3 inf -> 1.5707963267948966 -inf +acos1010 acos -2.3 nan -> nan nan +acos1011 acos 2.3 nan -> nan nan +acos1012 acos -inf 2.3 -> 3.1415926535897931 -inf +acos1013 acos -inf 0.0 -> 3.1415926535897931 -inf +acos1014 acos inf 2.3 -> 0.0 -inf +acos1015 acos inf 0.0 -> 0.0 -inf +acos1016 acos -inf inf -> 2.3561944901923448 -inf +acos1017 acos inf inf -> 0.78539816339744828 -inf +acos1018 acos inf nan -> nan inf ignore-imag-sign +acos1019 acos -inf nan -> nan inf ignore-imag-sign +acos1020 acos nan 0.0 -> nan nan +acos1021 acos nan 2.3 -> nan nan +acos1022 acos nan inf -> nan -inf +acos1023 acos nan nan -> nan nan +acos1024 acos -2.3 -inf -> 1.5707963267948966 inf +acos1025 acos -0.0 -inf -> 1.5707963267948966 inf +acos1026 acos 0.0 -inf -> 1.5707963267948966 inf +acos1027 acos 2.3 -inf -> 1.5707963267948966 inf +acos1028 acos -inf -2.3 -> 3.1415926535897931 inf +acos1029 acos -inf -0.0 -> 3.1415926535897931 inf +acos1030 acos inf -2.3 -> 0.0 inf +acos1031 acos inf -0.0 -> 0.0 inf +acos1032 acos -inf -inf -> 2.3561944901923448 inf +acos1033 acos inf -inf -> 0.78539816339744828 inf +acos1034 acos nan -0.0 -> nan nan +acos1035 acos nan -2.3 -> nan nan +acos1036 acos nan -inf -> nan inf + + +-------------------------------------- +-- acosh: Inverse hyperbolic cosine -- +-------------------------------------- + +-- zeros +acosh0000 acosh 0.0 0.0 -> 0.0 1.5707963267948966 +acosh0001 acosh 0.0 -0.0 -> 0.0 -1.5707963267948966 +acosh0002 acosh -0.0 0.0 -> 0.0 1.5707963267948966 +acosh0003 acosh -0.0 -0.0 -> 0.0 -1.5707963267948966 + +-- branch points: +/-1 +acosh0010 acosh 1.0 0.0 -> 0.0 0.0 +acosh0011 acosh 1.0 -0.0 -> 0.0 -0.0 +acosh0012 acosh -1.0 0.0 -> 0.0 3.1415926535897931 +acosh0013 acosh -1.0 -0.0 -> 0.0 -3.1415926535897931 + +-- values along both sides of real axis +acosh0020 acosh -9.8813129168249309e-324 0.0 -> 0.0 1.5707963267948966 +acosh0021 acosh -9.8813129168249309e-324 -0.0 -> 0.0 -1.5707963267948966 +acosh0022 acosh -1e-305 0.0 -> 0.0 1.5707963267948966 +acosh0023 acosh -1e-305 -0.0 -> 0.0 -1.5707963267948966 +acosh0024 acosh -1e-150 0.0 -> 0.0 1.5707963267948966 +acosh0025 acosh -1e-150 -0.0 -> 0.0 -1.5707963267948966 +acosh0026 acosh -9.9999999999999998e-17 0.0 -> 0.0 1.5707963267948968 +acosh0027 acosh -9.9999999999999998e-17 -0.0 -> 0.0 -1.5707963267948968 +acosh0028 acosh -0.001 0.0 -> 0.0 1.5717963269615634 +acosh0029 acosh -0.001 -0.0 -> 0.0 -1.5717963269615634 +acosh0030 acosh -0.57899999999999996 0.0 -> 0.0 2.1882979816120667 +acosh0031 acosh -0.57899999999999996 -0.0 -> 0.0 -2.1882979816120667 +acosh0032 acosh -0.99999999999999989 0.0 -> 0.0 3.1415926386886319 +acosh0033 acosh -0.99999999999999989 -0.0 -> 0.0 -3.1415926386886319 +acosh0034 acosh -1.0000000000000002 0.0 -> 2.1073424255447014e-08 3.1415926535897931 +acosh0035 acosh -1.0000000000000002 -0.0 -> 2.1073424255447014e-08 -3.1415926535897931 +acosh0036 acosh -1.0009999999999999 0.0 -> 0.044717633608306849 3.1415926535897931 +acosh0037 acosh -1.0009999999999999 -0.0 -> 0.044717633608306849 -3.1415926535897931 +acosh0038 acosh -2.0 0.0 -> 1.3169578969248168 3.1415926535897931 +acosh0039 acosh -2.0 -0.0 -> 1.3169578969248168 -3.1415926535897931 +acosh0040 acosh -23.0 0.0 -> 3.8281684713331012 3.1415926535897931 +acosh0041 acosh -23.0 -0.0 -> 3.8281684713331012 -3.1415926535897931 +acosh0042 acosh -10000000000000000.0 0.0 -> 37.534508668464674 3.1415926535897931 +acosh0043 acosh -10000000000000000.0 -0.0 -> 37.534508668464674 -3.1415926535897931 +acosh0044 acosh -9.9999999999999998e+149 0.0 -> 346.08091112966679 3.1415926535897931 +acosh0045 acosh -9.9999999999999998e+149 -0.0 -> 346.08091112966679 -3.1415926535897931 +acosh0046 acosh -1.0000000000000001e+299 0.0 -> 689.16608998577965 3.1415926535897931 +acosh0047 acosh -1.0000000000000001e+299 -0.0 -> 689.16608998577965 -3.1415926535897931 +acosh0048 acosh 9.8813129168249309e-324 0.0 -> 0.0 1.5707963267948966 +acosh0049 acosh 9.8813129168249309e-324 -0.0 -> 0.0 -1.5707963267948966 +acosh0050 acosh 1e-305 0.0 -> 0.0 1.5707963267948966 +acosh0051 acosh 1e-305 -0.0 -> 0.0 -1.5707963267948966 +acosh0052 acosh 1e-150 0.0 -> 0.0 1.5707963267948966 +acosh0053 acosh 1e-150 -0.0 -> 0.0 -1.5707963267948966 +acosh0054 acosh 9.9999999999999998e-17 0.0 -> 0.0 1.5707963267948966 +acosh0055 acosh 9.9999999999999998e-17 -0.0 -> 0.0 -1.5707963267948966 +acosh0056 acosh 0.001 0.0 -> 0.0 1.56979632662823 +acosh0057 acosh 0.001 -0.0 -> 0.0 -1.56979632662823 +acosh0058 acosh 0.57899999999999996 0.0 -> 0.0 0.95329467197772655 +acosh0059 acosh 0.57899999999999996 -0.0 -> 0.0 -0.95329467197772655 +acosh0060 acosh 0.99999999999999989 0.0 -> 0.0 1.4901161193847656e-08 +acosh0061 acosh 0.99999999999999989 -0.0 -> 0.0 -1.4901161193847656e-08 +acosh0062 acosh 1.0000000000000002 0.0 -> 2.1073424255447014e-08 0.0 +acosh0063 acosh 1.0000000000000002 -0.0 -> 2.1073424255447014e-08 -0.0 +acosh0064 acosh 1.0009999999999999 0.0 -> 0.044717633608306849 0.0 +acosh0065 acosh 1.0009999999999999 -0.0 -> 0.044717633608306849 -0.0 +acosh0066 acosh 2.0 0.0 -> 1.3169578969248168 0.0 +acosh0067 acosh 2.0 -0.0 -> 1.3169578969248168 -0.0 +acosh0068 acosh 23.0 0.0 -> 3.8281684713331012 0.0 +acosh0069 acosh 23.0 -0.0 -> 3.8281684713331012 -0.0 +acosh0070 acosh 10000000000000000.0 0.0 -> 37.534508668464674 0.0 +acosh0071 acosh 10000000000000000.0 -0.0 -> 37.534508668464674 -0.0 +acosh0072 acosh 9.9999999999999998e+149 0.0 -> 346.08091112966679 0.0 +acosh0073 acosh 9.9999999999999998e+149 -0.0 -> 346.08091112966679 -0.0 +acosh0074 acosh 1.0000000000000001e+299 0.0 -> 689.16608998577965 0.0 +acosh0075 acosh 1.0000000000000001e+299 -0.0 -> 689.16608998577965 -0.0 + +-- random inputs +acosh0100 acosh -1.4328589581250843 -1.8370347775558309 -> 1.5526962646549587 -2.190250168435786 +acosh0101 acosh -0.31075819156220957 -1.0772555786839297 -> 0.95139168286193709 -1.7812228089636479 +acosh0102 acosh -1.9044776578070453 -20.485370158932124 -> 3.7177411088932359 -1.6633888745861227 +acosh0103 acosh -0.075642506000858742 -21965976320.873051 -> 24.505907742881991 -1.5707963267983402 +acosh0104 acosh -1.6162271181056307 -3.0369343458696099 -> 1.9407057262861227 -2.0429549461750209 +acosh0105 acosh -0.3103780280298063 0.00018054880018078987 -> 0.00018992877058761416 1.886386995096728 +acosh0106 acosh -9159468751.5897655 5.8014747664273649 -> 23.631201197959193 3.1415926529564078 +acosh0107 acosh -0.037739157550933884 0.21841357493510705 -> 0.21685844960602488 1.6076735133449402 +acosh0108 acosh -8225991.0508394297 0.28318543008913644 -> 16.615956520420287 3.1415926191641019 +acosh0109 acosh -35.620070502302639 0.31303237005015 -> 4.2658980006943965 3.1328013255541873 +acosh0110 acosh 96.729939906820917 -0.029345228372365334 -> 5.2650434775863548 -0.00030338895866972843 +acosh0111 acosh 0.59656024007966491 -2.0412294654163978 -> 1.4923002024287835 -1.312568421900338 +acosh0112 acosh 109.29384112677828 -0.00015454863061533812 -> 5.3871662961545477 -1.4141245154061214e-06 +acosh0113 acosh 8.6705651969361597 -3.6723631649787465 -> 2.9336180958363545 -0.40267362031872861 +acosh0114 acosh 1.8101646445052686 -0.012345132721855478 -> 1.1997148566285769 -0.0081813912760150265 +acosh0115 acosh 52.56897195025288 0.001113916065985443 -> 4.6551827622264135 2.1193445872040307e-05 +acosh0116 acosh 0.28336786164214739 355643992457.40485 -> 27.290343226816528 1.5707963267940999 +acosh0117 acosh 0.73876621291911437 2.8828594541104322e-20 -> 4.2774820978159067e-20 0.73955845836827927 +acosh0118 acosh 0.025865471781718878 37125746064318.492 -> 31.938478989418012 1.5707963267948959 +acosh0119 acosh 2.2047353511780132 0.074712248143489271 -> 1.4286403248698021 0.037997904971626598 + +-- values near infinity +acosh0200 acosh 8.1548592876467785e+307 9.0943779335951128e+307 -> 710.08944620800605 0.83981165425478954 +acosh0201 acosh 1.4237229680972531e+308 -1.0336966617874858e+308 -> 710.4543331094759 -0.6279972876348755 +acosh0202 acosh -1.5014526899738939e+308 1.5670700378448792e+308 -> 710.66420706795464 2.3348137299106697 +acosh0203 acosh -1.0939040375213928e+308 -1.0416960351127978e+308 -> 710.30182863115886 -2.380636147787027 +acosh0204 acosh 0.0 1.476062433559588e+308 -> 710.27873384716929 1.5707963267948966 +acosh0205 acosh -0.0 6.2077210326221094e+307 -> 709.41256457484769 1.5707963267948966 +acosh0206 acosh 0.0 -1.5621899909968308e+308 -> 710.33544449990734 -1.5707963267948966 +acosh0207 acosh -0.0 -8.3556624833839122e+307 -> 709.70971018048317 -1.5707963267948966 +acosh0208 acosh 1.3067079752499342e+308 0.0 -> 710.15686680107228 0.0 +acosh0209 acosh 1.5653640340214026e+308 -0.0 -> 710.33747422926706 -0.0 +acosh0210 acosh -6.9011375992290636e+307 0.0 -> 709.51845699719922 3.1415926535897931 +acosh0211 acosh -9.9539576809926973e+307 -0.0 -> 709.88474095870185 -3.1415926535897931 +acosh0212 acosh 7.6449598518914925e+307 9.5706540768268358 -> 709.62081731754802 1.2518906916769345e-307 +acosh0213 acosh 5.4325410972602197e+307 -7.8064807816522706 -> 709.279177727925 -1.4369851312471974e-307 +acosh0214 acosh -1.1523626112360465e+308 7.0617510038869336 -> 710.03117010216909 3.1415926535897931 +acosh0215 acosh -1.1685027786862599e+308 -5.1568558357925625 -> 710.04507907571417 -3.1415926535897931 +acosh0216 acosh 3.0236370339788721 1.7503248720096417e+308 -> 710.44915723458064 1.5707963267948966 +acosh0217 acosh 6.6108007926031149 -9.1469968225806149e+307 -> 709.80019633903328 -1.5707963267948966 +acosh0218 acosh -5.1096262905623959 6.4484926785412395e+307 -> 709.45061713997973 1.5707963267948966 +acosh0219 acosh -2.8080920608735846 -1.7716118836519368e+308 -> 710.46124562363445 -1.5707963267948966 + +-- values near 0 +acosh0220 acosh 4.5560530326699304e-317 7.3048989121436657e-318 -> 7.3048989121436657e-318 1.5707963267948966 +acosh0221 acosh 4.8754274133585331e-314 -9.8469794897684199e-315 -> 9.8469794897684199e-315 -1.5707963267948966 +acosh0222 acosh -4.6748876009960097e-312 9.7900342887557606e-318 -> 9.7900342887557606e-318 1.5707963267948966 +acosh0223 acosh -4.3136871538399236e-320 -4.9406564584124654e-323 -> 4.9406564584124654e-323 -1.5707963267948966 +acosh0224 acosh 0.0 4.3431013866496774e-314 -> 4.3431013866496774e-314 1.5707963267948966 +acosh0225 acosh -0.0 6.0147334335829184e-317 -> 6.0147334335829184e-317 1.5707963267948966 +acosh0226 acosh 0.0 -1.2880291387081297e-320 -> 1.2880291387081297e-320 -1.5707963267948966 +acosh0227 acosh -0.0 -1.4401563976534621e-317 -> 1.4401563976534621e-317 -1.5707963267948966 +acosh0228 acosh 1.3689680570863091e-313 0.0 -> 0.0 1.5707963267948966 +acosh0229 acosh 1.5304346893494371e-312 -0.0 -> 0.0 -1.5707963267948966 +acosh0230 acosh -3.7450175954766488e-320 0.0 -> 0.0 1.5707963267948966 +acosh0231 acosh -8.4250563080885801e-311 -0.0 -> 0.0 -1.5707963267948966 + +-- special values +acosh1000 acosh 0.0 0.0 -> 0.0 1.5707963267948966 +acosh1001 acosh -0.0 0.0 -> 0.0 1.5707963267948966 +acosh1002 acosh 0.0 inf -> inf 1.5707963267948966 +acosh1003 acosh 2.3 inf -> inf 1.5707963267948966 +acosh1004 acosh -0.0 inf -> inf 1.5707963267948966 +acosh1005 acosh -2.3 inf -> inf 1.5707963267948966 +acosh1006 acosh 0.0 nan -> nan nan +acosh1007 acosh 2.3 nan -> nan nan +acosh1008 acosh -0.0 nan -> nan nan +acosh1009 acosh -2.3 nan -> nan nan +acosh1010 acosh -inf 0.0 -> inf 3.1415926535897931 +acosh1011 acosh -inf 2.3 -> inf 3.1415926535897931 +acosh1012 acosh inf 0.0 -> inf 0.0 +acosh1013 acosh inf 2.3 -> inf 0.0 +acosh1014 acosh -inf inf -> inf 2.3561944901923448 +acosh1015 acosh inf inf -> inf 0.78539816339744828 +acosh1016 acosh inf nan -> inf nan +acosh1017 acosh -inf nan -> inf nan +acosh1018 acosh nan 0.0 -> nan nan +acosh1019 acosh nan 2.3 -> nan nan +acosh1020 acosh nan inf -> inf nan +acosh1021 acosh nan nan -> nan nan +acosh1022 acosh 0.0 -0.0 -> 0.0 -1.5707963267948966 +acosh1023 acosh -0.0 -0.0 -> 0.0 -1.5707963267948966 +acosh1024 acosh 0.0 -inf -> inf -1.5707963267948966 +acosh1025 acosh 2.3 -inf -> inf -1.5707963267948966 +acosh1026 acosh -0.0 -inf -> inf -1.5707963267948966 +acosh1027 acosh -2.3 -inf -> inf -1.5707963267948966 +acosh1028 acosh -inf -0.0 -> inf -3.1415926535897931 +acosh1029 acosh -inf -2.3 -> inf -3.1415926535897931 +acosh1030 acosh inf -0.0 -> inf -0.0 +acosh1031 acosh inf -2.3 -> inf -0.0 +acosh1032 acosh -inf -inf -> inf -2.3561944901923448 +acosh1033 acosh inf -inf -> inf -0.78539816339744828 +acosh1034 acosh nan -0.0 -> nan nan +acosh1035 acosh nan -2.3 -> nan nan +acosh1036 acosh nan -inf -> inf nan + + +------------------------ +-- asin: Inverse sine -- +------------------------ + +-- zeros +asin0000 asin 0.0 0.0 -> 0.0 0.0 +asin0001 asin 0.0 -0.0 -> 0.0 -0.0 +asin0002 asin -0.0 0.0 -> -0.0 0.0 +asin0003 asin -0.0 -0.0 -> -0.0 -0.0 + +-- branch points: +/-1 +asin0010 asin 1.0 0.0 -> 1.5707963267948966 0.0 +asin0011 asin 1.0 -0.0 -> 1.5707963267948966 -0.0 +asin0012 asin -1.0 0.0 -> -1.5707963267948966 0.0 +asin0013 asin -1.0 -0.0 -> -1.5707963267948966 -0.0 + +-- values along both sides of real axis +asin0020 asin -9.8813129168249309e-324 0.0 -> -9.8813129168249309e-324 0.0 +asin0021 asin -9.8813129168249309e-324 -0.0 -> -9.8813129168249309e-324 -0.0 +asin0022 asin -1e-305 0.0 -> -1e-305 0.0 +asin0023 asin -1e-305 -0.0 -> -1e-305 -0.0 +asin0024 asin -1e-150 0.0 -> -1e-150 0.0 +asin0025 asin -1e-150 -0.0 -> -1e-150 -0.0 +asin0026 asin -9.9999999999999998e-17 0.0 -> -9.9999999999999998e-17 0.0 +asin0027 asin -9.9999999999999998e-17 -0.0 -> -9.9999999999999998e-17 -0.0 +asin0028 asin -0.001 0.0 -> -0.0010000001666667416 0.0 +asin0029 asin -0.001 -0.0 -> -0.0010000001666667416 -0.0 +asin0030 asin -0.57899999999999996 0.0 -> -0.61750165481717001 0.0 +asin0031 asin -0.57899999999999996 -0.0 -> -0.61750165481717001 -0.0 +asin0032 asin -0.99999999999999989 0.0 -> -1.5707963118937354 0.0 +asin0033 asin -0.99999999999999989 -0.0 -> -1.5707963118937354 -0.0 +asin0034 asin -1.0000000000000002 0.0 -> -1.5707963267948966 2.1073424255447014e-08 +asin0035 asin -1.0000000000000002 -0.0 -> -1.5707963267948966 -2.1073424255447014e-08 +asin0036 asin -1.0009999999999999 0.0 -> -1.5707963267948966 0.044717633608306849 +asin0037 asin -1.0009999999999999 -0.0 -> -1.5707963267948966 -0.044717633608306849 +asin0038 asin -2.0 0.0 -> -1.5707963267948966 1.3169578969248168 +asin0039 asin -2.0 -0.0 -> -1.5707963267948966 -1.3169578969248168 +asin0040 asin -23.0 0.0 -> -1.5707963267948966 3.8281684713331012 +asin0041 asin -23.0 -0.0 -> -1.5707963267948966 -3.8281684713331012 +asin0042 asin -10000000000000000.0 0.0 -> -1.5707963267948966 37.534508668464674 +asin0043 asin -10000000000000000.0 -0.0 -> -1.5707963267948966 -37.534508668464674 +asin0044 asin -9.9999999999999998e+149 0.0 -> -1.5707963267948966 346.08091112966679 +asin0045 asin -9.9999999999999998e+149 -0.0 -> -1.5707963267948966 -346.08091112966679 +asin0046 asin -1.0000000000000001e+299 0.0 -> -1.5707963267948966 689.16608998577965 +asin0047 asin -1.0000000000000001e+299 -0.0 -> -1.5707963267948966 -689.16608998577965 +asin0048 asin 9.8813129168249309e-324 0.0 -> 9.8813129168249309e-324 0.0 +asin0049 asin 9.8813129168249309e-324 -0.0 -> 9.8813129168249309e-324 -0.0 +asin0050 asin 1e-305 0.0 -> 1e-305 0.0 +asin0051 asin 1e-305 -0.0 -> 1e-305 -0.0 +asin0052 asin 1e-150 0.0 -> 1e-150 0.0 +asin0053 asin 1e-150 -0.0 -> 1e-150 -0.0 +asin0054 asin 9.9999999999999998e-17 0.0 -> 9.9999999999999998e-17 0.0 +asin0055 asin 9.9999999999999998e-17 -0.0 -> 9.9999999999999998e-17 -0.0 +asin0056 asin 0.001 0.0 -> 0.0010000001666667416 0.0 +asin0057 asin 0.001 -0.0 -> 0.0010000001666667416 -0.0 +asin0058 asin 0.57899999999999996 0.0 -> 0.61750165481717001 0.0 +asin0059 asin 0.57899999999999996 -0.0 -> 0.61750165481717001 -0.0 +asin0060 asin 0.99999999999999989 0.0 -> 1.5707963118937354 0.0 +asin0061 asin 0.99999999999999989 -0.0 -> 1.5707963118937354 -0.0 +asin0062 asin 1.0000000000000002 0.0 -> 1.5707963267948966 2.1073424255447014e-08 +asin0063 asin 1.0000000000000002 -0.0 -> 1.5707963267948966 -2.1073424255447014e-08 +asin0064 asin 1.0009999999999999 0.0 -> 1.5707963267948966 0.044717633608306849 +asin0065 asin 1.0009999999999999 -0.0 -> 1.5707963267948966 -0.044717633608306849 +asin0066 asin 2.0 0.0 -> 1.5707963267948966 1.3169578969248168 +asin0067 asin 2.0 -0.0 -> 1.5707963267948966 -1.3169578969248168 +asin0068 asin 23.0 0.0 -> 1.5707963267948966 3.8281684713331012 +asin0069 asin 23.0 -0.0 -> 1.5707963267948966 -3.8281684713331012 +asin0070 asin 10000000000000000.0 0.0 -> 1.5707963267948966 37.534508668464674 +asin0071 asin 10000000000000000.0 -0.0 -> 1.5707963267948966 -37.534508668464674 +asin0072 asin 9.9999999999999998e+149 0.0 -> 1.5707963267948966 346.08091112966679 +asin0073 asin 9.9999999999999998e+149 -0.0 -> 1.5707963267948966 -346.08091112966679 +asin0074 asin 1.0000000000000001e+299 0.0 -> 1.5707963267948966 689.16608998577965 +asin0075 asin 1.0000000000000001e+299 -0.0 -> 1.5707963267948966 -689.16608998577965 + +-- random inputs +asin0100 asin -1.5979555835086083 -0.15003009814595247 -> -1.4515369557405788 -1.0544476399790823 +asin0101 asin -0.57488225895317679 -9.6080397838952743e-13 -> -0.61246024460412851 -1.174238005400403e-12 +asin0102 asin -3.6508087930516249 -0.36027527093220152 -> -1.4685890605305874 -1.9742273007152038 +asin0103 asin -1.5238659792326819 -1.1360813516996364 -> -0.86080051691147275 -1.3223742205689195 +asin0104 asin -1592.0639045555306 -0.72362427935018236 -> -1.5703418071175179 -8.0659336918729228 +asin0105 asin -0.19835471371312019 4.2131508416697709 -> -0.045777831019935149 2.1461732751933171 +asin0106 asin -1.918471054430213 0.40603305079779234 -> -1.3301396585791556 1.30263642314981 +asin0107 asin -254495.01623373642 0.71084414434470822 -> -1.5707935336394359 13.140183712762321 +asin0108 asin -0.31315882715691157 3.9647994288429866 -> -0.076450403840916004 2.0889762138713457 +asin0109 asin -0.90017064284720816 1.2530659485907105 -> -0.53466509741943447 1.1702811557577 +asin0110 asin 2.1615181696571075 -0.14058647488229523 -> 1.4976166323896871 -1.4085811039334604 +asin0111 asin 1.2104749210707795 -0.85732484485298999 -> 0.83913071588343924 -1.0681719250525901 +asin0112 asin 1.7059733185128891 -0.84032966373156581 -> 1.0510900815816229 -1.2967979791361652 +asin0113 asin 9.9137085017290687 -1.4608383970250893 -> 1.4237704820128891 -2.995414677560686 +asin0114 asin 117.12344751041495 -5453908091.5334015 -> 2.1475141411392012e-08 -23.112745450217066 +asin0115 asin 0.081041187798029227 0.067054349860173196 -> 0.080946786856771813 0.067223991060639698 +asin0116 asin 46.635472322049949 2.3835190718056678 -> 1.5197194940010779 4.5366989600972083 +asin0117 asin 3907.0687961127105 19.144021886390181 -> 1.5658965233083235 8.9637018715924217 +asin0118 asin 1.0889312322308273 509.01577883554768 -> 0.0021392803817829316 6.9256294494524706 +asin0119 asin 0.10851518277509224 1.5612510908217476 -> 0.058491014243902621 1.2297075725621327 + +-- values near infinity +asin0200 asin 1.5230241998821499e+308 5.5707228994084525e+307 -> 1.2201446370892068 710.37283486535966 +asin0201 asin 8.1334317698672204e+307 -9.2249425197872451e+307 -> 0.72259991284020042 -710.0962453049026 +asin0202 asin -9.9138506659241768e+307 6.701544526434995e+307 -> -0.97637511742194594 710.06887486671371 +asin0203 asin -1.4141298868173842e+308 -5.401505134514191e+307 -> -1.2059319055160587 -710.30396478954628 +asin0204 asin 0.0 9.1618092977897431e+307 -> 0.0 709.80181441050593 +asin0205 asin -0.0 6.8064342551939755e+307 -> -0.0 709.50463910853489 +asin0206 asin 0.0 -6.4997516454798215e+307 -> 0.0 -709.45853469751592 +asin0207 asin -0.0 -1.6767449053345242e+308 -> -0.0 -710.4062101803022 +asin0208 asin 5.4242749957378916e+307 0.0 -> 1.5707963267948966 709.27765497888902 +asin0209 asin 9.5342145121164749e+307 -0.0 -> 1.5707963267948966 -709.84165758595907 +asin0210 asin -7.0445698006201847e+307 0.0 -> -1.5707963267948966 709.53902780872136 +asin0211 asin -1.0016025569769706e+308 -0.0 -> -1.5707963267948966 -709.89095709697881 +asin0212 asin 1.6552203778877204e+308 0.48761543336249491 -> 1.5707963267948966 710.39328998153474 +asin0213 asin 1.2485712830384869e+308 -4.3489311161278899 -> 1.5707963267948966 -710.1113557467786 +asin0214 asin -1.5117842813353125e+308 5.123452666102434 -> -1.5707963267948966 710.30264641923031 +asin0215 asin -1.3167634313008016e+308 -0.52939679793528982 -> -1.5707963267948966 -710.16453260239768 +asin0216 asin 0.80843929176985907 1.0150851827767876e+308 -> 7.9642507396113875e-309 709.90432835561637 +asin0217 asin 8.2544809829680901 -1.7423548140539474e+308 -> 4.7375430746865733e-308 -710.44459336242164 +asin0218 asin -5.2499000118824295 4.6655578977512214e+307 -> -1.1252459249113292e-307 709.1269781491103 +asin0219 asin -5.9904782760833433 -4.7315689314781163e+307 -> -1.2660659419394637e-307 -709.14102757522312 + +-- special values +asin1000 asin -0.0 0.0 -> -0.0 0.0 +asin1001 asin 0.0 0.0 -> 0.0 0.0 +asin1002 asin -0.0 -0.0 -> -0.0 -0.0 +asin1003 asin 0.0 -0.0 -> 0.0 -0.0 +asin1004 asin -inf 0.0 -> -1.5707963267948966 inf +asin1005 asin -inf 2.2999999999999998 -> -1.5707963267948966 inf +asin1006 asin nan 0.0 -> nan nan +asin1007 asin nan 2.2999999999999998 -> nan nan +asin1008 asin -0.0 inf -> -0.0 inf +asin1009 asin -2.2999999999999998 inf -> -0.0 inf +asin1010 asin -inf inf -> -0.78539816339744828 inf +asin1011 asin nan inf -> nan inf +asin1012 asin -0.0 nan -> -0.0 nan +asin1013 asin -2.2999999999999998 nan -> nan nan +asin1014 asin -inf nan -> nan inf ignore-imag-sign +asin1015 asin nan nan -> nan nan +asin1016 asin inf 0.0 -> 1.5707963267948966 inf +asin1017 asin inf 2.2999999999999998 -> 1.5707963267948966 inf +asin1018 asin 0.0 inf -> 0.0 inf +asin1019 asin 2.2999999999999998 inf -> 0.0 inf +asin1020 asin inf inf -> 0.78539816339744828 inf +asin1021 asin 0.0 nan -> 0.0 nan +asin1022 asin 2.2999999999999998 nan -> nan nan +asin1023 asin inf nan -> nan inf ignore-imag-sign +asin1024 asin inf -0.0 -> 1.5707963267948966 -inf +asin1025 asin inf -2.2999999999999998 -> 1.5707963267948966 -inf +asin1026 asin nan -0.0 -> nan nan +asin1027 asin nan -2.2999999999999998 -> nan nan +asin1028 asin 0.0 -inf -> 0.0 -inf +asin1029 asin 2.2999999999999998 -inf -> 0.0 -inf +asin1030 asin inf -inf -> 0.78539816339744828 -inf +asin1031 asin nan -inf -> nan -inf +asin1032 asin -inf -0.0 -> -1.5707963267948966 -inf +asin1033 asin -inf -2.2999999999999998 -> -1.5707963267948966 -inf +asin1034 asin -0.0 -inf -> -0.0 -inf +asin1035 asin -2.2999999999999998 -inf -> -0.0 -inf +asin1036 asin -inf -inf -> -0.78539816339744828 -inf + + +------------------------------------ +-- asinh: Inverse hyperbolic sine -- +------------------------------------ + +-- zeros +asinh0000 asinh 0.0 0.0 -> 0.0 0.0 +asinh0001 asinh 0.0 -0.0 -> 0.0 -0.0 +asinh0002 asinh -0.0 0.0 -> -0.0 0.0 +asinh0003 asinh -0.0 -0.0 -> -0.0 -0.0 + +-- branch points: +/-i +asinh0010 asinh 0.0 1.0 -> 0.0 1.5707963267948966 +asinh0011 asinh 0.0 -1.0 -> 0.0 -1.5707963267948966 +asinh0012 asinh -0.0 1.0 -> -0.0 1.5707963267948966 +asinh0013 asinh -0.0 -1.0 -> -0.0 -1.5707963267948966 + +-- values along both sides of imaginary axis +asinh0020 asinh 0.0 -9.8813129168249309e-324 -> 0.0 -9.8813129168249309e-324 +asinh0021 asinh -0.0 -9.8813129168249309e-324 -> -0.0 -9.8813129168249309e-324 +asinh0022 asinh 0.0 -1e-305 -> 0.0 -1e-305 +asinh0023 asinh -0.0 -1e-305 -> -0.0 -1e-305 +asinh0024 asinh 0.0 -1e-150 -> 0.0 -1e-150 +asinh0025 asinh -0.0 -1e-150 -> -0.0 -1e-150 +asinh0026 asinh 0.0 -9.9999999999999998e-17 -> 0.0 -9.9999999999999998e-17 +asinh0027 asinh -0.0 -9.9999999999999998e-17 -> -0.0 -9.9999999999999998e-17 +asinh0028 asinh 0.0 -0.001 -> 0.0 -0.0010000001666667416 +asinh0029 asinh -0.0 -0.001 -> -0.0 -0.0010000001666667416 +asinh0030 asinh 0.0 -0.57899999999999996 -> 0.0 -0.61750165481717001 +asinh0031 asinh -0.0 -0.57899999999999996 -> -0.0 -0.61750165481717001 +asinh0032 asinh 0.0 -0.99999999999999989 -> 0.0 -1.5707963118937354 +asinh0033 asinh -0.0 -0.99999999999999989 -> -0.0 -1.5707963118937354 +asinh0034 asinh 0.0 -1.0000000000000002 -> 2.1073424255447014e-08 -1.5707963267948966 +asinh0035 asinh -0.0 -1.0000000000000002 -> -2.1073424255447014e-08 -1.5707963267948966 +asinh0036 asinh 0.0 -1.0009999999999999 -> 0.044717633608306849 -1.5707963267948966 +asinh0037 asinh -0.0 -1.0009999999999999 -> -0.044717633608306849 -1.5707963267948966 +asinh0038 asinh 0.0 -2.0 -> 1.3169578969248168 -1.5707963267948966 +asinh0039 asinh -0.0 -2.0 -> -1.3169578969248168 -1.5707963267948966 +asinh0040 asinh 0.0 -20.0 -> 3.6882538673612966 -1.5707963267948966 +asinh0041 asinh -0.0 -20.0 -> -3.6882538673612966 -1.5707963267948966 +asinh0042 asinh 0.0 -10000000000000000.0 -> 37.534508668464674 -1.5707963267948966 +asinh0043 asinh -0.0 -10000000000000000.0 -> -37.534508668464674 -1.5707963267948966 +asinh0044 asinh 0.0 -9.9999999999999998e+149 -> 346.08091112966679 -1.5707963267948966 +asinh0045 asinh -0.0 -9.9999999999999998e+149 -> -346.08091112966679 -1.5707963267948966 +asinh0046 asinh 0.0 -1.0000000000000001e+299 -> 689.16608998577965 -1.5707963267948966 +asinh0047 asinh -0.0 -1.0000000000000001e+299 -> -689.16608998577965 -1.5707963267948966 +asinh0048 asinh 0.0 9.8813129168249309e-324 -> 0.0 9.8813129168249309e-324 +asinh0049 asinh -0.0 9.8813129168249309e-324 -> -0.0 9.8813129168249309e-324 +asinh0050 asinh 0.0 1e-305 -> 0.0 1e-305 +asinh0051 asinh -0.0 1e-305 -> -0.0 1e-305 +asinh0052 asinh 0.0 1e-150 -> 0.0 1e-150 +asinh0053 asinh -0.0 1e-150 -> -0.0 1e-150 +asinh0054 asinh 0.0 9.9999999999999998e-17 -> 0.0 9.9999999999999998e-17 +asinh0055 asinh -0.0 9.9999999999999998e-17 -> -0.0 9.9999999999999998e-17 +asinh0056 asinh 0.0 0.001 -> 0.0 0.0010000001666667416 +asinh0057 asinh -0.0 0.001 -> -0.0 0.0010000001666667416 +asinh0058 asinh 0.0 0.57899999999999996 -> 0.0 0.61750165481717001 +asinh0059 asinh -0.0 0.57899999999999996 -> -0.0 0.61750165481717001 +asinh0060 asinh 0.0 0.99999999999999989 -> 0.0 1.5707963118937354 +asinh0061 asinh -0.0 0.99999999999999989 -> -0.0 1.5707963118937354 +asinh0062 asinh 0.0 1.0000000000000002 -> 2.1073424255447014e-08 1.5707963267948966 +asinh0063 asinh -0.0 1.0000000000000002 -> -2.1073424255447014e-08 1.5707963267948966 +asinh0064 asinh 0.0 1.0009999999999999 -> 0.044717633608306849 1.5707963267948966 +asinh0065 asinh -0.0 1.0009999999999999 -> -0.044717633608306849 1.5707963267948966 +asinh0066 asinh 0.0 2.0 -> 1.3169578969248168 1.5707963267948966 +asinh0067 asinh -0.0 2.0 -> -1.3169578969248168 1.5707963267948966 +asinh0068 asinh 0.0 20.0 -> 3.6882538673612966 1.5707963267948966 +asinh0069 asinh -0.0 20.0 -> -3.6882538673612966 1.5707963267948966 +asinh0070 asinh 0.0 10000000000000000.0 -> 37.534508668464674 1.5707963267948966 +asinh0071 asinh -0.0 10000000000000000.0 -> -37.534508668464674 1.5707963267948966 +asinh0072 asinh 0.0 9.9999999999999998e+149 -> 346.08091112966679 1.5707963267948966 +asinh0073 asinh -0.0 9.9999999999999998e+149 -> -346.08091112966679 1.5707963267948966 +asinh0074 asinh 0.0 1.0000000000000001e+299 -> 689.16608998577965 1.5707963267948966 +asinh0075 asinh -0.0 1.0000000000000001e+299 -> -689.16608998577965 1.5707963267948966 + +-- random inputs +asinh0100 asinh -0.5946402853710423 -0.044506548910000145 -> -0.56459775392653022 -0.038256221441536356 +asinh0101 asinh -0.19353958046180916 -0.017489624793193454 -> -0.19237926804196651 -0.017171741895336792 +asinh0102 asinh -0.033117585138955893 -8.5256414015933757 -> -2.8327758348650969 -1.5668848791092411 +asinh0103 asinh -1.5184043184035716 -0.73491245339073275 -> -1.2715891419764005 -0.39204624408542355 +asinh0104 asinh -0.60716120271208818 -0.28900743958436542 -> -0.59119299421187232 -0.24745931678118135 +asinh0105 asinh -0.0237177865112429 2.8832601052166313 -> -1.7205820772413236 1.5620261702963094 +asinh0106 asinh -2.3906812342743979 2.6349216848574013 -> -1.9609636249445124 0.8142142660574706 +asinh0107 asinh -0.0027605019787620517 183.85588476550555 -> -5.9072920005445066 1.5707813120847871 +asinh0108 asinh -0.99083661164404713 0.028006797051617648 -> -0.8750185251283995 0.019894099615994653 +asinh0109 asinh -3.0362951937986393 0.86377266758504867 -> -1.8636030714685221 0.26475058859950168 +asinh0110 asinh 0.34438464536152769 -0.71603790174885029 -> 0.43985415690734164 -0.71015037409294324 +asinh0111 asinh 4.4925124413876256 -60604595352.871613 -> 25.520783738612078 -1.5707963267207683 +asinh0112 asinh 2.3213991428170337 -7.5459667007307258 -> 2.7560464993451643 -1.270073210856117 +asinh0113 asinh 0.21291939741682028 -1.2720428814784408 -> 0.77275088137338266 -1.3182099250896895 +asinh0114 asinh 6.6447359379455957 -0.97196191666946996 -> 2.602830695139672 -0.14368247412319965 +asinh0115 asinh 7.1326256655083746 2.1516360452706857 -> 2.7051146374367212 0.29051701669727581 +asinh0116 asinh 0.18846550905063442 3.4705348585339832 -> 1.917697875799296 1.514155593347924 +asinh0117 asinh 0.19065075303281598 0.26216814548222012 -> 0.19603050785932474 0.26013422809614117 +asinh0118 asinh 2.0242004665739719 0.70510281647495787 -> 1.4970366212896002 0.30526007200481453 +asinh0119 asinh 37.336596461576057 717.29157391678234 -> 7.269981997945294 1.5187910219576033 + +-- values near infinity +asinh0200 asinh 1.0760517500874541e+308 1.1497786241240167e+308 -> 710.34346055651815 0.81850936961793475 +asinh0201 asinh 1.1784839328845529e+308 -1.6478429586716638e+308 -> 710.59536255783678 -0.94996311735607697 +asinh0202 asinh -4.8777682248909193e+307 1.4103736217538474e+308 -> -710.28970147376992 1.2378239519096443 +asinh0203 asinh -1.2832478903233108e+308 -1.5732392613155698e+308 -> -710.59750164290745 -0.88657181439322452 +asinh0204 asinh 0.0 6.8431383856345372e+307 -> 709.51001718444604 1.5707963267948966 +asinh0205 asinh -0.0 8.601822432238051e+307 -> -709.73874482126689 1.5707963267948966 +asinh0206 asinh 0.0 -5.5698396067303782e+307 -> 709.30413698733742 -1.5707963267948966 +asinh0207 asinh -0.0 -7.1507777734621804e+307 -> -709.55399186002705 -1.5707963267948966 +asinh0208 asinh 1.6025136110019349e+308 0.0 -> 710.3609292261076 0.0 +asinh0209 asinh 1.3927819858239114e+308 -0.0 -> 710.22065899832899 -0.0 +asinh0210 asinh -6.0442994056210995e+307 0.0 -> -709.38588631057621 0.0 +asinh0211 asinh -1.2775271979042634e+308 -0.0 -> -710.13428215553972 -0.0 +asinh0212 asinh 1.0687496260268489e+308 1.0255615699476961 -> 709.95584521407841 9.5959010882679093e-309 +asinh0213 asinh 1.0050967333370962e+308 -0.87668970117333433 -> 709.89443961168183 -8.7224410556242882e-309 +asinh0214 asinh -5.7161452814862392e+307 8.2377808413450122 -> -709.33006540611166 1.4411426644501116e-307 +asinh0215 asinh -8.2009040727653315e+307 -6.407409526654976 -> -709.69101513070109 -7.8130526461510088e-308 +asinh0216 asinh 6.4239368496483982 1.6365990821551427e+308 -> 710.38197618101287 1.5707963267948966 +asinh0217 asinh 5.4729111423315882 -1.1227237438144211e+308 -> 710.00511346983546 -1.5707963267948966 +asinh0218 asinh -8.3455818297412723 1.443172020182019e+308 -> -710.25619930551818 1.5707963267948966 +asinh0219 asinh -2.6049726230372441 -1.7952291144022702e+308 -> -710.47448847685644 -1.5707963267948966 + +-- values near 0 +asinh0220 asinh 1.2940113339664088e-314 6.9169190417774516e-323 -> 1.2940113339664088e-314 6.9169190417774516e-323 +asinh0221 asinh 2.3848478863874649e-315 -3.1907655025717717e-310 -> 2.3848478863874649e-315 -3.1907655025717717e-310 +asinh0222 asinh -3.0097643679641622e-316 4.6936236354918422e-322 -> -3.0097643679641622e-316 4.6936236354918422e-322 +asinh0223 asinh -1.787997087755751e-308 -8.5619622834902341e-310 -> -1.787997087755751e-308 -8.5619622834902341e-310 +asinh0224 asinh 0.0 1.2491433448427325e-314 -> 0.0 1.2491433448427325e-314 +asinh0225 asinh -0.0 2.5024072154538062e-308 -> -0.0 2.5024072154538062e-308 +asinh0226 asinh 0.0 -2.9643938750474793e-323 -> 0.0 -2.9643938750474793e-323 +asinh0227 asinh -0.0 -2.9396905927554169e-320 -> -0.0 -2.9396905927554169e-320 +asinh0228 asinh 5.64042930029359e-317 0.0 -> 5.64042930029359e-317 0.0 +asinh0229 asinh 3.3833911866596068e-318 -0.0 -> 3.3833911866596068e-318 -0.0 +asinh0230 asinh -4.9406564584124654e-324 0.0 -> -4.9406564584124654e-324 0.0 +asinh0231 asinh -2.2211379227994845e-308 -0.0 -> -2.2211379227994845e-308 -0.0 + +-- special values +asinh1000 asinh 0.0 0.0 -> 0.0 0.0 +asinh1001 asinh 0.0 -0.0 -> 0.0 -0.0 +asinh1002 asinh -0.0 0.0 -> -0.0 0.0 +asinh1003 asinh -0.0 -0.0 -> -0.0 -0.0 +asinh1004 asinh 0.0 inf -> inf 1.5707963267948966 +asinh1005 asinh 2.3 inf -> inf 1.5707963267948966 +asinh1006 asinh 0.0 nan -> nan nan +asinh1007 asinh 2.3 nan -> nan nan +asinh1008 asinh inf 0.0 -> inf 0.0 +asinh1009 asinh inf 2.3 -> inf 0.0 +asinh1010 asinh inf inf -> inf 0.78539816339744828 +asinh1011 asinh inf nan -> inf nan +asinh1012 asinh nan 0.0 -> nan 0.0 +asinh1013 asinh nan 2.3 -> nan nan +asinh1014 asinh nan inf -> inf nan ignore-real-sign +asinh1015 asinh nan nan -> nan nan +asinh1016 asinh 0.0 -inf -> inf -1.5707963267948966 +asinh1017 asinh 2.3 -inf -> inf -1.5707963267948966 +asinh1018 asinh inf -0.0 -> inf -0.0 +asinh1019 asinh inf -2.3 -> inf -0.0 +asinh1020 asinh inf -inf -> inf -0.78539816339744828 +asinh1021 asinh nan -0.0 -> nan -0.0 +asinh1022 asinh nan -2.3 -> nan nan +asinh1023 asinh nan -inf -> inf nan ignore-real-sign +asinh1024 asinh -0.0 -inf -> -inf -1.5707963267948966 +asinh1025 asinh -2.3 -inf -> -inf -1.5707963267948966 +asinh1026 asinh -0.0 nan -> nan nan +asinh1027 asinh -2.3 nan -> nan nan +asinh1028 asinh -inf -0.0 -> -inf -0.0 +asinh1029 asinh -inf -2.3 -> -inf -0.0 +asinh1030 asinh -inf -inf -> -inf -0.78539816339744828 +asinh1031 asinh -inf nan -> -inf nan +asinh1032 asinh -0.0 inf -> -inf 1.5707963267948966 +asinh1033 asinh -2.3 inf -> -inf 1.5707963267948966 +asinh1034 asinh -inf 0.0 -> -inf 0.0 +asinh1035 asinh -inf 2.3 -> -inf 0.0 +asinh1036 asinh -inf inf -> -inf 0.78539816339744828 + + +--------------------------- +-- atan: Inverse tangent -- +--------------------------- + +-- zeros +atan0000 atan 0.0 0.0 -> 0.0 0.0 +atan0001 atan 0.0 -0.0 -> 0.0 -0.0 +atan0002 atan -0.0 0.0 -> -0.0 0.0 +atan0003 atan -0.0 -0.0 -> -0.0 -0.0 + +-- values along both sides of imaginary axis +atan0010 atan 0.0 -9.8813129168249309e-324 -> 0.0 -9.8813129168249309e-324 +atan0011 atan -0.0 -9.8813129168249309e-324 -> -0.0 -9.8813129168249309e-324 +atan0012 atan 0.0 -1e-305 -> 0.0 -1e-305 +atan0013 atan -0.0 -1e-305 -> -0.0 -1e-305 +atan0014 atan 0.0 -1e-150 -> 0.0 -1e-150 +atan0015 atan -0.0 -1e-150 -> -0.0 -1e-150 +atan0016 atan 0.0 -9.9999999999999998e-17 -> 0.0 -9.9999999999999998e-17 +atan0017 atan -0.0 -9.9999999999999998e-17 -> -0.0 -9.9999999999999998e-17 +atan0018 atan 0.0 -0.001 -> 0.0 -0.0010000003333335333 +atan0019 atan -0.0 -0.001 -> -0.0 -0.0010000003333335333 +atan0020 atan 0.0 -0.57899999999999996 -> 0.0 -0.6609570902866303 +atan0021 atan -0.0 -0.57899999999999996 -> -0.0 -0.6609570902866303 +atan0022 atan 0.0 -0.99999999999999989 -> 0.0 -18.714973875118524 +atan0023 atan -0.0 -0.99999999999999989 -> -0.0 -18.714973875118524 +atan0024 atan 0.0 -1.0000000000000002 -> 1.5707963267948966 -18.36840028483855 +atan0025 atan -0.0 -1.0000000000000002 -> -1.5707963267948966 -18.36840028483855 +atan0026 atan 0.0 -1.0009999999999999 -> 1.5707963267948966 -3.8007011672919218 +atan0027 atan -0.0 -1.0009999999999999 -> -1.5707963267948966 -3.8007011672919218 +atan0028 atan 0.0 -2.0 -> 1.5707963267948966 -0.54930614433405489 +atan0029 atan -0.0 -2.0 -> -1.5707963267948966 -0.54930614433405489 +atan0030 atan 0.0 -20.0 -> 1.5707963267948966 -0.050041729278491265 +atan0031 atan -0.0 -20.0 -> -1.5707963267948966 -0.050041729278491265 +atan0032 atan 0.0 -10000000000000000.0 -> 1.5707963267948966 -9.9999999999999998e-17 +atan0033 atan -0.0 -10000000000000000.0 -> -1.5707963267948966 -9.9999999999999998e-17 +atan0034 atan 0.0 -9.9999999999999998e+149 -> 1.5707963267948966 -1e-150 +atan0035 atan -0.0 -9.9999999999999998e+149 -> -1.5707963267948966 -1e-150 +atan0036 atan 0.0 -1.0000000000000001e+299 -> 1.5707963267948966 -9.9999999999999999e-300 +atan0037 atan -0.0 -1.0000000000000001e+299 -> -1.5707963267948966 -9.9999999999999999e-300 +atan0038 atan 0.0 9.8813129168249309e-324 -> 0.0 9.8813129168249309e-324 +atan0039 atan -0.0 9.8813129168249309e-324 -> -0.0 9.8813129168249309e-324 +atan0040 atan 0.0 1e-305 -> 0.0 1e-305 +atan0041 atan -0.0 1e-305 -> -0.0 1e-305 +atan0042 atan 0.0 1e-150 -> 0.0 1e-150 +atan0043 atan -0.0 1e-150 -> -0.0 1e-150 +atan0044 atan 0.0 9.9999999999999998e-17 -> 0.0 9.9999999999999998e-17 +atan0045 atan -0.0 9.9999999999999998e-17 -> -0.0 9.9999999999999998e-17 +atan0046 atan 0.0 0.001 -> 0.0 0.0010000003333335333 +atan0047 atan -0.0 0.001 -> -0.0 0.0010000003333335333 +atan0048 atan 0.0 0.57899999999999996 -> 0.0 0.6609570902866303 +atan0049 atan -0.0 0.57899999999999996 -> -0.0 0.6609570902866303 +atan0050 atan 0.0 0.99999999999999989 -> 0.0 18.714973875118524 +atan0051 atan -0.0 0.99999999999999989 -> -0.0 18.714973875118524 +atan0052 atan 0.0 1.0000000000000002 -> 1.5707963267948966 18.36840028483855 +atan0053 atan -0.0 1.0000000000000002 -> -1.5707963267948966 18.36840028483855 +atan0054 atan 0.0 1.0009999999999999 -> 1.5707963267948966 3.8007011672919218 +atan0055 atan -0.0 1.0009999999999999 -> -1.5707963267948966 3.8007011672919218 +atan0056 atan 0.0 2.0 -> 1.5707963267948966 0.54930614433405489 +atan0057 atan -0.0 2.0 -> -1.5707963267948966 0.54930614433405489 +atan0058 atan 0.0 20.0 -> 1.5707963267948966 0.050041729278491265 +atan0059 atan -0.0 20.0 -> -1.5707963267948966 0.050041729278491265 +atan0060 atan 0.0 10000000000000000.0 -> 1.5707963267948966 9.9999999999999998e-17 +atan0061 atan -0.0 10000000000000000.0 -> -1.5707963267948966 9.9999999999999998e-17 +atan0062 atan 0.0 9.9999999999999998e+149 -> 1.5707963267948966 1e-150 +atan0063 atan -0.0 9.9999999999999998e+149 -> -1.5707963267948966 1e-150 +atan0064 atan 0.0 1.0000000000000001e+299 -> 1.5707963267948966 9.9999999999999999e-300 +atan0065 atan -0.0 1.0000000000000001e+299 -> -1.5707963267948966 9.9999999999999999e-300 + +-- random inputs +atan0100 atan -0.32538873661060214 -1.5530461550412578 -> -1.3682728427554227 -0.69451401598762041 +atan0101 atan -0.45863393495197929 -4799.1747094903594 -> -1.5707963068820623 -0.00020836916050636145 +atan0102 atan -8.3006999685976162 -2.6788890251790938 -> -1.4619862771810199 -0.034811669653327826 +atan0103 atan -1.8836307682985314 -1.1441976638861771 -> -1.1839984370871612 -0.20630956157312796 +atan0104 atan -0.00063230482407491669 -4.9312520961829485 -> -1.5707692093223147 -0.20563867743008304 +atan0105 atan -0.84278137150065946 179012.37493146997 -> -1.5707963267685969 5.5862059836425272e-06 +atan0106 atan -0.95487853984049287 14.311334539886177 -> -1.5661322859434561 0.069676024526232005 +atan0107 atan -1.3513252539663239 6.0500727021632198e-08 -> -0.93371676315220975 2.140800269742656e-08 +atan0108 atan -0.20566254458595795 0.11933771944159823 -> -0.20556463711174916 0.11493405387141732 +atan0109 atan -0.58563718795408559 0.64438965423212868 -> -0.68361089300233124 0.46759762751800249 +atan0110 atan 48.479267751948292 -78.386382460112543 -> 1.5650888770910523 -0.0092276811373297584 +atan0111 atan 1.0575373914056061 -0.75988012377296987 -> 0.94430886722043594 -0.31915698126703118 +atan0112 atan 4444810.4314677203 -0.56553404593942558 -> 1.5707961018134231 -2.8625446437701909e-14 +atan0113 atan 0.010101405082520009 -0.032932668550282478 -> 0.01011202676646334 -0.032941214776834996 +atan0114 atan 1.5353585300154911 -2.1947099346796519 -> 1.3400310739206394 -0.29996003607449045 +atan0115 atan 0.21869457055670882 9.9915684254007093 -> 1.5685846078876444 0.1003716881759439 +atan0116 atan 0.17783290150246836 0.064334689863650957 -> 0.17668728064286277 0.062435808728873846 +atan0117 atan 15.757474087615918 383.57262142534 -> 1.5706894060369621 0.0026026817278826603 +atan0118 atan 10.587017408533317 0.21720238081843438 -> 1.4766594681336236 0.0019199097383010061 +atan0119 atan 0.86026078678781204 0.1230148609359502 -> 0.7147259322534929 0.070551221954286605 + +-- values near infinity +atan0200 atan 7.8764397011195798e+307 8.1647921137746308e+307 -> 1.5707963267948966 6.3439446939604493e-309 +atan0201 atan 1.5873698696131487e+308 -1.0780367422960641e+308 -> 1.5707963267948966 -2.9279309368530781e-309 +atan0202 atan -1.5844551864825834e+308 1.0290657809098675e+308 -> -1.5707963267948966 2.8829614736961417e-309 +atan0203 atan -1.3168792562524032e+308 -9.088432341614825e+307 -> -1.5707963267948966 -3.5499373057390056e-309 +atan0204 atan 0.0 1.0360465742258337e+308 -> 1.5707963267948966 9.6520757355646018e-309 +atan0205 atan -0.0 1.0045063210373196e+308 -> -1.5707963267948966 9.955138947929503e-309 +atan0206 atan 0.0 -9.5155296715763696e+307 -> 1.5707963267948966 -1.050913648020118e-308 +atan0207 atan -0.0 -1.5565700490496501e+308 -> -1.5707963267948966 -6.4243816114189071e-309 +atan0208 atan 1.2956339389525244e+308 0.0 -> 1.5707963267948966 0.0 +atan0209 atan 1.4408126243772151e+308 -0.0 -> 1.5707963267948966 -0.0 +atan0210 atan -1.0631786461936417e+308 0.0 -> -1.5707963267948966 0.0 +atan0211 atan -1.0516056964171069e+308 -0.0 -> -1.5707963267948966 -0.0 +atan0212 atan 1.236162319603838e+308 4.6827953496242936 -> 1.5707963267948966 0.0 +atan0213 atan 7.000516472897218e+307 -5.8631608017844163 -> 1.5707963267948966 -0.0 +atan0214 atan -1.5053444003338508e+308 5.1199197268420313 -> -1.5707963267948966 0.0 +atan0215 atan -1.399172518147259e+308 -3.5687766472913673 -> -1.5707963267948966 -0.0 +atan0216 atan 8.1252833070803021 6.2782953917343822e+307 -> 1.5707963267948966 1.5927890256908564e-308 +atan0217 atan 2.8034285947515167 -1.3378049775753878e+308 -> 1.5707963267948966 -7.4749310756219562e-309 +atan0218 atan -1.4073509988974953 1.6776381785968355e+308 -> -1.5707963267948966 5.9607608646364569e-309 +atan0219 atan -2.7135551527592119 -1.281567445525738e+308 -> -1.5707963267948966 -7.8029447727565326e-309 + +-- imaginary part = +/-1, real part tiny +atan0300 atan -1e-150 -1.0 -> -0.78539816339744828 -173.04045556483339 +atan0301 atan 1e-155 1.0 -> 0.78539816339744828 178.79691829731851 +atan0302 atan 9.9999999999999999e-161 -1.0 -> 0.78539816339744828 -184.55338102980363 +atan0303 atan -1e-165 1.0 -> -0.78539816339744828 190.30984376228875 +atan0304 atan -9.9998886718268301e-321 -1.0 -> -0.78539816339744828 -368.76019403576692 + +-- special values +atan1000 atan -0.0 0.0 -> -0.0 0.0 +atan1001 atan nan 0.0 -> nan 0.0 +atan1002 atan -0.0 1.0 -> -0.0 inf divide-by-zero +atan1003 atan -inf 0.0 -> -1.5707963267948966 0.0 +atan1004 atan -inf 2.2999999999999998 -> -1.5707963267948966 0.0 +atan1005 atan nan 2.2999999999999998 -> nan nan +atan1006 atan -0.0 inf -> -1.5707963267948966 0.0 +atan1007 atan -2.2999999999999998 inf -> -1.5707963267948966 0.0 +atan1008 atan -inf inf -> -1.5707963267948966 0.0 +atan1009 atan nan inf -> nan 0.0 +atan1010 atan -0.0 nan -> nan nan +atan1011 atan -2.2999999999999998 nan -> nan nan +atan1012 atan -inf nan -> -1.5707963267948966 0.0 ignore-imag-sign +atan1013 atan nan nan -> nan nan +atan1014 atan 0.0 0.0 -> 0.0 0.0 +atan1015 atan 0.0 1.0 -> 0.0 inf divide-by-zero +atan1016 atan inf 0.0 -> 1.5707963267948966 0.0 +atan1017 atan inf 2.2999999999999998 -> 1.5707963267948966 0.0 +atan1018 atan 0.0 inf -> 1.5707963267948966 0.0 +atan1019 atan 2.2999999999999998 inf -> 1.5707963267948966 0.0 +atan1020 atan inf inf -> 1.5707963267948966 0.0 +atan1021 atan 0.0 nan -> nan nan +atan1022 atan 2.2999999999999998 nan -> nan nan +atan1023 atan inf nan -> 1.5707963267948966 0.0 ignore-imag-sign +atan1024 atan 0.0 -0.0 -> 0.0 -0.0 +atan1025 atan nan -0.0 -> nan -0.0 +atan1026 atan 0.0 -1.0 -> 0.0 -inf divide-by-zero +atan1027 atan inf -0.0 -> 1.5707963267948966 -0.0 +atan1028 atan inf -2.2999999999999998 -> 1.5707963267948966 -0.0 +atan1029 atan nan -2.2999999999999998 -> nan nan +atan1030 atan 0.0 -inf -> 1.5707963267948966 -0.0 +atan1031 atan 2.2999999999999998 -inf -> 1.5707963267948966 -0.0 +atan1032 atan inf -inf -> 1.5707963267948966 -0.0 +atan1033 atan nan -inf -> nan -0.0 +atan1034 atan -0.0 -0.0 -> -0.0 -0.0 +atan1035 atan -0.0 -1.0 -> -0.0 -inf divide-by-zero +atan1036 atan -inf -0.0 -> -1.5707963267948966 -0.0 +atan1037 atan -inf -2.2999999999999998 -> -1.5707963267948966 -0.0 +atan1038 atan -0.0 -inf -> -1.5707963267948966 -0.0 +atan1039 atan -2.2999999999999998 -inf -> -1.5707963267948966 -0.0 +atan1040 atan -inf -inf -> -1.5707963267948966 -0.0 + + +--------------------------------------- +-- atanh: Inverse hyperbolic tangent -- +--------------------------------------- + +-- zeros +atanh0000 atanh 0.0 0.0 -> 0.0 0.0 +atanh0001 atanh 0.0 -0.0 -> 0.0 -0.0 +atanh0002 atanh -0.0 0.0 -> -0.0 0.0 +atanh0003 atanh -0.0 -0.0 -> -0.0 -0.0 + +-- values along both sides of real axis +atanh0010 atanh -9.8813129168249309e-324 0.0 -> -9.8813129168249309e-324 0.0 +atanh0011 atanh -9.8813129168249309e-324 -0.0 -> -9.8813129168249309e-324 -0.0 +atanh0012 atanh -1e-305 0.0 -> -1e-305 0.0 +atanh0013 atanh -1e-305 -0.0 -> -1e-305 -0.0 +atanh0014 atanh -1e-150 0.0 -> -1e-150 0.0 +atanh0015 atanh -1e-150 -0.0 -> -1e-150 -0.0 +atanh0016 atanh -9.9999999999999998e-17 0.0 -> -9.9999999999999998e-17 0.0 +atanh0017 atanh -9.9999999999999998e-17 -0.0 -> -9.9999999999999998e-17 -0.0 +atanh0018 atanh -0.001 0.0 -> -0.0010000003333335333 0.0 +atanh0019 atanh -0.001 -0.0 -> -0.0010000003333335333 -0.0 +atanh0020 atanh -0.57899999999999996 0.0 -> -0.6609570902866303 0.0 +atanh0021 atanh -0.57899999999999996 -0.0 -> -0.6609570902866303 -0.0 +atanh0022 atanh -0.99999999999999989 0.0 -> -18.714973875118524 0.0 +atanh0023 atanh -0.99999999999999989 -0.0 -> -18.714973875118524 -0.0 +atanh0024 atanh -1.0000000000000002 0.0 -> -18.36840028483855 1.5707963267948966 +atanh0025 atanh -1.0000000000000002 -0.0 -> -18.36840028483855 -1.5707963267948966 +atanh0026 atanh -1.0009999999999999 0.0 -> -3.8007011672919218 1.5707963267948966 +atanh0027 atanh -1.0009999999999999 -0.0 -> -3.8007011672919218 -1.5707963267948966 +atanh0028 atanh -2.0 0.0 -> -0.54930614433405489 1.5707963267948966 +atanh0029 atanh -2.0 -0.0 -> -0.54930614433405489 -1.5707963267948966 +atanh0030 atanh -23.0 0.0 -> -0.043505688494814884 1.5707963267948966 +atanh0031 atanh -23.0 -0.0 -> -0.043505688494814884 -1.5707963267948966 +atanh0032 atanh -10000000000000000.0 0.0 -> -9.9999999999999998e-17 1.5707963267948966 +atanh0033 atanh -10000000000000000.0 -0.0 -> -9.9999999999999998e-17 -1.5707963267948966 +atanh0034 atanh -9.9999999999999998e+149 0.0 -> -1e-150 1.5707963267948966 +atanh0035 atanh -9.9999999999999998e+149 -0.0 -> -1e-150 -1.5707963267948966 +atanh0036 atanh -1.0000000000000001e+299 0.0 -> -9.9999999999999999e-300 1.5707963267948966 +atanh0037 atanh -1.0000000000000001e+299 -0.0 -> -9.9999999999999999e-300 -1.5707963267948966 +atanh0038 atanh 9.8813129168249309e-324 0.0 -> 9.8813129168249309e-324 0.0 +atanh0039 atanh 9.8813129168249309e-324 -0.0 -> 9.8813129168249309e-324 -0.0 +atanh0040 atanh 1e-305 0.0 -> 1e-305 0.0 +atanh0041 atanh 1e-305 -0.0 -> 1e-305 -0.0 +atanh0042 atanh 1e-150 0.0 -> 1e-150 0.0 +atanh0043 atanh 1e-150 -0.0 -> 1e-150 -0.0 +atanh0044 atanh 9.9999999999999998e-17 0.0 -> 9.9999999999999998e-17 0.0 +atanh0045 atanh 9.9999999999999998e-17 -0.0 -> 9.9999999999999998e-17 -0.0 +atanh0046 atanh 0.001 0.0 -> 0.0010000003333335333 0.0 +atanh0047 atanh 0.001 -0.0 -> 0.0010000003333335333 -0.0 +atanh0048 atanh 0.57899999999999996 0.0 -> 0.6609570902866303 0.0 +atanh0049 atanh 0.57899999999999996 -0.0 -> 0.6609570902866303 -0.0 +atanh0050 atanh 0.99999999999999989 0.0 -> 18.714973875118524 0.0 +atanh0051 atanh 0.99999999999999989 -0.0 -> 18.714973875118524 -0.0 +atanh0052 atanh 1.0000000000000002 0.0 -> 18.36840028483855 1.5707963267948966 +atanh0053 atanh 1.0000000000000002 -0.0 -> 18.36840028483855 -1.5707963267948966 +atanh0054 atanh 1.0009999999999999 0.0 -> 3.8007011672919218 1.5707963267948966 +atanh0055 atanh 1.0009999999999999 -0.0 -> 3.8007011672919218 -1.5707963267948966 +atanh0056 atanh 2.0 0.0 -> 0.54930614433405489 1.5707963267948966 +atanh0057 atanh 2.0 -0.0 -> 0.54930614433405489 -1.5707963267948966 +atanh0058 atanh 23.0 0.0 -> 0.043505688494814884 1.5707963267948966 +atanh0059 atanh 23.0 -0.0 -> 0.043505688494814884 -1.5707963267948966 +atanh0060 atanh 10000000000000000.0 0.0 -> 9.9999999999999998e-17 1.5707963267948966 +atanh0061 atanh 10000000000000000.0 -0.0 -> 9.9999999999999998e-17 -1.5707963267948966 +atanh0062 atanh 9.9999999999999998e+149 0.0 -> 1e-150 1.5707963267948966 +atanh0063 atanh 9.9999999999999998e+149 -0.0 -> 1e-150 -1.5707963267948966 +atanh0064 atanh 1.0000000000000001e+299 0.0 -> 9.9999999999999999e-300 1.5707963267948966 +atanh0065 atanh 1.0000000000000001e+299 -0.0 -> 9.9999999999999999e-300 -1.5707963267948966 + +-- random inputs +atanh0100 atanh -0.54460925980633501 -0.54038050126721027 -> -0.41984265808446974 -0.60354153938352828 +atanh0101 atanh -1.6934614269829051 -0.48807386108113621 -> -0.58592769102243281 -1.3537837470975898 +atanh0102 atanh -1.3467293985501207 -0.47868354895395876 -> -0.69961624370709985 -1.1994450156570076 +atanh0103 atanh -5.6142232418984888 -544551613.39307702 -> -1.8932657550925744e-17 -1.5707963249585235 +atanh0104 atanh -0.011841460381263651 -3.259978899823385 -> -0.0010183936547405188 -1.2731614020743838 +atanh0105 atanh -0.0073345736950029532 0.35821949670922248 -> -0.0065004869024682466 0.34399359971920895 +atanh0106 atanh -13.866782244320014 0.9541129545860273 -> -0.071896852055058899 1.5658322704631409 +atanh0107 atanh -708.59964982780775 21.984802159266675 -> -0.0014098779074189741 1.5707525842838959 +atanh0108 atanh -30.916832076030602 1.3691897138829843 -> -0.032292682045743676 1.5693652094847115 +atanh0109 atanh -0.57461806339861754 0.29534797443913063 -> -0.56467464472482765 0.39615612824172625 +atanh0110 atanh 0.40089246737415685 -1.632285984300659 -> 0.1063832707890608 -1.0402821335326482 +atanh0111 atanh 2119.6167688262176 -1.5383653437377242e+17 -> 8.9565008518382049e-32 -1.5707963267948966 +atanh0112 atanh 756.86017850941641 -6.6064087133223817 -> 0.0013211481136820046 -1.5707847948702234 +atanh0113 atanh 4.0490617718041602 -2.5784456791040652e-12 -> 0.25218425538553618 -1.5707963267947291 +atanh0114 atanh 10.589254957173523 -0.13956391149624509 -> 0.094700890282197664 -1.5695407140217623 +atanh0115 atanh 1.0171187553160499 0.70766113465354019 -> 0.55260251975367791 0.96619711116641682 +atanh0116 atanh 0.031645502527750849 0.067319983726544394 -> 0.031513018344086742 0.067285437670549036 +atanh0117 atanh 0.13670177624994517 0.43240089361857947 -> 0.11538933151017253 0.41392008145336212 +atanh0118 atanh 0.64173899243596688 2.9008577686695256 -> 0.065680142424134405 1.2518535724053921 +atanh0119 atanh 0.19313813528025942 38.799619150741869 -> 0.00012820765917366644 1.5450292202823612 + +-- values near infinity +atanh0200 atanh 5.3242646831347954e+307 1.3740396080084153e+308 -> 2.4519253616695576e-309 1.5707963267948966 +atanh0201 atanh 1.158701641241358e+308 -6.5579268873375853e+307 -> 6.5365375267795098e-309 -1.5707963267948966 +atanh0202 atanh -1.3435325735762247e+308 9.8947369259601547e+307 -> -4.8256680906589956e-309 1.5707963267948966 +atanh0203 atanh -1.4359857522598942e+308 -9.4701204702391004e+307 -> -4.8531282262872645e-309 -1.5707963267948966 +atanh0204 atanh 0.0 5.6614181068098497e+307 -> 0.0 1.5707963267948966 +atanh0205 atanh -0.0 6.9813212721450139e+307 -> -0.0 1.5707963267948966 +atanh0206 atanh 0.0 -7.4970613060311453e+307 -> 0.0 -1.5707963267948966 +atanh0207 atanh -0.0 -1.5280601880314068e+308 -> -0.0 -1.5707963267948966 +atanh0208 atanh 8.2219472336000745e+307 0.0 -> 1.2162568933954813e-308 1.5707963267948966 +atanh0209 atanh 1.4811519617280899e+308 -0.0 -> 6.7515017083951325e-309 -1.5707963267948966 +atanh0210 atanh -1.2282016263598785e+308 0.0 -> -8.1419856360537615e-309 1.5707963267948966 +atanh0211 atanh -1.0616427760154426e+308 -0.0 -> -9.4193642399489563e-309 -1.5707963267948966 +atanh0212 atanh 1.2971536510180682e+308 5.2847948452333293 -> 7.7091869510998328e-309 1.5707963267948966 +atanh0213 atanh 1.1849860977411851e+308 -7.9781906447459949 -> 8.4389175696339014e-309 -1.5707963267948966 +atanh0214 atanh -1.4029969422586635e+308 0.93891986543663375 -> -7.127599283218073e-309 1.5707963267948966 +atanh0215 atanh -4.7508098912248211e+307 -8.2702421247039908 -> -2.1049042645278043e-308 -1.5707963267948966 +atanh0216 atanh 8.2680742115769998 8.1153898410918065e+307 -> 0.0 1.5707963267948966 +atanh0217 atanh 1.2575325146218885 -1.4746679147661649e+308 -> 0.0 -1.5707963267948966 +atanh0218 atanh -2.4618803682310899 1.3781522717005568e+308 -> -0.0 1.5707963267948966 +atanh0219 atanh -4.0952386694788112 -1.231083376353703e+308 -> -0.0 -1.5707963267948966 + +-- values near 0 +atanh0220 atanh 3.8017563659811628e-314 2.6635484239074319e-312 -> 3.8017563659811628e-314 2.6635484239074319e-312 +atanh0221 atanh 1.7391110733611878e-321 -4.3547800672541419e-313 -> 1.7391110733611878e-321 -4.3547800672541419e-313 +atanh0222 atanh -5.9656816081325078e-317 9.9692253555416263e-313 -> -5.9656816081325078e-317 9.9692253555416263e-313 +atanh0223 atanh -6.5606671178400239e-313 -2.1680936406357335e-309 -> -6.5606671178400239e-313 -2.1680936406357335e-309 +atanh0224 atanh 0.0 2.5230944401820779e-319 -> 0.0 2.5230944401820779e-319 +atanh0225 atanh -0.0 5.6066569490064658e-320 -> -0.0 5.6066569490064658e-320 +atanh0226 atanh 0.0 -2.4222487249468377e-317 -> 0.0 -2.4222487249468377e-317 +atanh0227 atanh -0.0 -3.0861101089206037e-316 -> -0.0 -3.0861101089206037e-316 +atanh0228 atanh 3.1219222884393986e-310 0.0 -> 3.1219222884393986e-310 0.0 +atanh0229 atanh 9.8926337564976196e-309 -0.0 -> 9.8926337564976196e-309 -0.0 +atanh0230 atanh -1.5462535092918154e-312 0.0 -> -1.5462535092918154e-312 0.0 +atanh0231 atanh -9.8813129168249309e-324 -0.0 -> -9.8813129168249309e-324 -0.0 + +-- real part = +/-1, imaginary part tiny +atanh0300 atanh 1.0 1e-153 -> 176.49433320432448 0.78539816339744828 +atanh0301 atanh 1.0 9.9999999999999997e-155 -> 177.64562575082149 0.78539816339744828 +atanh0302 atanh -1.0 1e-161 -> -185.70467357630065 0.78539816339744828 +atanh0303 atanh 1.0 -1e-165 -> 190.30984376228875 -0.78539816339744828 +atanh0304 atanh -1.0 -9.8813129168249309e-324 -> -372.22003596069061 -0.78539816339744828 + +-- special values +atanh1000 atanh 0.0 0.0 -> 0.0 0.0 +atanh1001 atanh 0.0 nan -> 0.0 nan +atanh1002 atanh 1.0 0.0 -> inf 0.0 divide-by-zero +atanh1003 atanh 0.0 inf -> 0.0 1.5707963267948966 +atanh1004 atanh 2.3 inf -> 0.0 1.5707963267948966 +atanh1005 atanh 2.3 nan -> nan nan +atanh1006 atanh inf 0.0 -> 0.0 1.5707963267948966 +atanh1007 atanh inf 2.3 -> 0.0 1.5707963267948966 +atanh1008 atanh inf inf -> 0.0 1.5707963267948966 +atanh1009 atanh inf nan -> 0.0 nan +atanh1010 atanh nan 0.0 -> nan nan +atanh1011 atanh nan 2.3 -> nan nan +atanh1012 atanh nan inf -> 0.0 1.5707963267948966 ignore-real-sign +atanh1013 atanh nan nan -> nan nan +atanh1014 atanh 0.0 -0.0 -> 0.0 -0.0 +atanh1015 atanh 1.0 -0.0 -> inf -0.0 divide-by-zero +atanh1016 atanh 0.0 -inf -> 0.0 -1.5707963267948966 +atanh1017 atanh 2.3 -inf -> 0.0 -1.5707963267948966 +atanh1018 atanh inf -0.0 -> 0.0 -1.5707963267948966 +atanh1019 atanh inf -2.3 -> 0.0 -1.5707963267948966 +atanh1020 atanh inf -inf -> 0.0 -1.5707963267948966 +atanh1021 atanh nan -0.0 -> nan nan +atanh1022 atanh nan -2.3 -> nan nan +atanh1023 atanh nan -inf -> 0.0 -1.5707963267948966 ignore-real-sign +atanh1024 atanh -0.0 -0.0 -> -0.0 -0.0 +atanh1025 atanh -0.0 nan -> -0.0 nan +atanh1026 atanh -1.0 -0.0 -> -inf -0.0 divide-by-zero +atanh1027 atanh -0.0 -inf -> -0.0 -1.5707963267948966 +atanh1028 atanh -2.3 -inf -> -0.0 -1.5707963267948966 +atanh1029 atanh -2.3 nan -> nan nan +atanh1030 atanh -inf -0.0 -> -0.0 -1.5707963267948966 +atanh1031 atanh -inf -2.3 -> -0.0 -1.5707963267948966 +atanh1032 atanh -inf -inf -> -0.0 -1.5707963267948966 +atanh1033 atanh -inf nan -> -0.0 nan +atanh1034 atanh -0.0 0.0 -> -0.0 0.0 +atanh1035 atanh -1.0 0.0 -> -inf 0.0 divide-by-zero +atanh1036 atanh -0.0 inf -> -0.0 1.5707963267948966 +atanh1037 atanh -2.3 inf -> -0.0 1.5707963267948966 +atanh1038 atanh -inf 0.0 -> -0.0 1.5707963267948966 +atanh1039 atanh -inf 2.3 -> -0.0 1.5707963267948966 +atanh1040 atanh -inf inf -> -0.0 1.5707963267948966 + + +---------------------------- +-- log: Natural logarithm -- +---------------------------- + +log0000 log 1.0 0.0 -> 0.0 0.0 +log0001 log 1.0 -0.0 -> 0.0 -0.0 +log0002 log -1.0 0.0 -> 0.0 3.1415926535897931 +log0003 log -1.0 -0.0 -> 0.0 -3.1415926535897931 +-- values along both sides of real axis +log0010 log -9.8813129168249309e-324 0.0 -> -743.74692474082133 3.1415926535897931 +log0011 log -9.8813129168249309e-324 -0.0 -> -743.74692474082133 -3.1415926535897931 +log0012 log -1e-305 0.0 -> -702.28845336318398 3.1415926535897931 +log0013 log -1e-305 -0.0 -> -702.28845336318398 -3.1415926535897931 +log0014 log -1e-150 0.0 -> -345.38776394910684 3.1415926535897931 +log0015 log -1e-150 -0.0 -> -345.38776394910684 -3.1415926535897931 +log0016 log -9.9999999999999998e-17 0.0 -> -36.841361487904734 3.1415926535897931 +log0017 log -9.9999999999999998e-17 -0.0 -> -36.841361487904734 -3.1415926535897931 +log0018 log -0.001 0.0 -> -6.9077552789821368 3.1415926535897931 +log0019 log -0.001 -0.0 -> -6.9077552789821368 -3.1415926535897931 +log0020 log -0.57899999999999996 0.0 -> -0.54645280140914188 3.1415926535897931 +log0021 log -0.57899999999999996 -0.0 -> -0.54645280140914188 -3.1415926535897931 +log0022 log -0.99999999999999989 0.0 -> -1.1102230246251565e-16 3.1415926535897931 +log0023 log -0.99999999999999989 -0.0 -> -1.1102230246251565e-16 -3.1415926535897931 +log0024 log -1.0000000000000002 0.0 -> 2.2204460492503128e-16 3.1415926535897931 +log0025 log -1.0000000000000002 -0.0 -> 2.2204460492503128e-16 -3.1415926535897931 +log0026 log -1.0009999999999999 0.0 -> 0.00099950033308342321 3.1415926535897931 +log0027 log -1.0009999999999999 -0.0 -> 0.00099950033308342321 -3.1415926535897931 +log0028 log -2.0 0.0 -> 0.69314718055994529 3.1415926535897931 +log0029 log -2.0 -0.0 -> 0.69314718055994529 -3.1415926535897931 +log0030 log -23.0 0.0 -> 3.1354942159291497 3.1415926535897931 +log0031 log -23.0 -0.0 -> 3.1354942159291497 -3.1415926535897931 +log0032 log -10000000000000000.0 0.0 -> 36.841361487904734 3.1415926535897931 +log0033 log -10000000000000000.0 -0.0 -> 36.841361487904734 -3.1415926535897931 +log0034 log -9.9999999999999998e+149 0.0 -> 345.38776394910684 3.1415926535897931 +log0035 log -9.9999999999999998e+149 -0.0 -> 345.38776394910684 -3.1415926535897931 +log0036 log -1.0000000000000001e+299 0.0 -> 688.47294280521965 3.1415926535897931 +log0037 log -1.0000000000000001e+299 -0.0 -> 688.47294280521965 -3.1415926535897931 +log0038 log 9.8813129168249309e-324 0.0 -> -743.74692474082133 0.0 +log0039 log 9.8813129168249309e-324 -0.0 -> -743.74692474082133 -0.0 +log0040 log 1e-305 0.0 -> -702.28845336318398 0.0 +log0041 log 1e-305 -0.0 -> -702.28845336318398 -0.0 +log0042 log 1e-150 0.0 -> -345.38776394910684 0.0 +log0043 log 1e-150 -0.0 -> -345.38776394910684 -0.0 +log0044 log 9.9999999999999998e-17 0.0 -> -36.841361487904734 0.0 +log0045 log 9.9999999999999998e-17 -0.0 -> -36.841361487904734 -0.0 +log0046 log 0.001 0.0 -> -6.9077552789821368 0.0 +log0047 log 0.001 -0.0 -> -6.9077552789821368 -0.0 +log0048 log 0.57899999999999996 0.0 -> -0.54645280140914188 0.0 +log0049 log 0.57899999999999996 -0.0 -> -0.54645280140914188 -0.0 +log0050 log 0.99999999999999989 0.0 -> -1.1102230246251565e-16 0.0 +log0051 log 0.99999999999999989 -0.0 -> -1.1102230246251565e-16 -0.0 +log0052 log 1.0000000000000002 0.0 -> 2.2204460492503128e-16 0.0 +log0053 log 1.0000000000000002 -0.0 -> 2.2204460492503128e-16 -0.0 +log0054 log 1.0009999999999999 0.0 -> 0.00099950033308342321 0.0 +log0055 log 1.0009999999999999 -0.0 -> 0.00099950033308342321 -0.0 +log0056 log 2.0 0.0 -> 0.69314718055994529 0.0 +log0057 log 2.0 -0.0 -> 0.69314718055994529 -0.0 +log0058 log 23.0 0.0 -> 3.1354942159291497 0.0 +log0059 log 23.0 -0.0 -> 3.1354942159291497 -0.0 +log0060 log 10000000000000000.0 0.0 -> 36.841361487904734 0.0 +log0061 log 10000000000000000.0 -0.0 -> 36.841361487904734 -0.0 +log0062 log 9.9999999999999998e+149 0.0 -> 345.38776394910684 0.0 +log0063 log 9.9999999999999998e+149 -0.0 -> 345.38776394910684 -0.0 +log0064 log 1.0000000000000001e+299 0.0 -> 688.47294280521965 0.0 +log0065 log 1.0000000000000001e+299 -0.0 -> 688.47294280521965 -0.0 + +-- random inputs +log0066 log -1.9830454945186191e-16 -2.0334448025673346 -> 0.70973130194329803 -1.5707963267948968 +log0067 log -0.96745853024741857 -0.84995816228299692 -> 0.25292811398722387 -2.4207570438536905 +log0068 log -0.1603644313948418 -0.2929942111041835 -> -1.0965857872427374 -2.0715870859971419 +log0069 log -0.15917913168438699 -0.25238799251132177 -> -1.2093477313249901 -2.1334784232033863 +log0070 log -0.68907818535078802 -3.0693105853476346 -> 1.1460398629184565 -1.7916403813913211 +log0071 log -17.268133447565589 6.8165120014604756 -> 2.9212694465974836 2.7656245081603164 +log0072 log -1.7153894479690328 26.434055372802636 -> 3.2767542953718003 1.6355986276341734 +log0073 log -8.0456794648936578e-06 0.19722758057570208 -> -1.6233969848296075 1.5708371206810101 +log0074 log -2.4306442691323173 0.6846919750700996 -> 0.92633592001969589 2.8670160576718331 +log0075 log -3.5488049250888194 0.45324040643185254 -> 1.2747008374256426 3.0145640007885111 +log0076 log 0.18418516851510189 -0.26062518836212617 -> -1.1421287121940344 -0.95558440841183434 +log0077 log 2.7124837795638399 -13.148769067133387 -> 2.5971659975706802 -1.3673583045209439 +log0078 log 3.6521275476169149e-13 -3.7820543023170673e-05 -> -10.182658136741569 -1.5707963171384316 +log0079 log 5.0877545813862239 -1.2834978326786852 -> 1.6576856213076328 -0.24711583497738485 +log0080 log 0.26477986808461512 -0.67659001194187429 -> -0.31944085207999973 -1.197773671987121 +log0081 log 0.0014754261398071962 5.3514691608205442 -> 1.6773711707153829 1.5705206219261802 +log0082 log 0.29667334462157885 0.00020056045042584795 -> -1.2151233667079588 0.00067603114168689204 +log0083 log 0.82104233671099425 3.9005387130133102 -> 1.3827918965299593 1.3633304701848363 +log0084 log 0.27268135358180667 124.42088110945804 -> 4.8236724223559229 1.5686047258789015 +log0085 log 0.0026286959168267485 0.47795808180573013 -> -0.73821712137809126 1.5652965360960087 + +-- values near infinity +log0100 log 1.0512025744003172e+308 7.2621669750664611e+307 -> 709.44123967814494 0.60455434048332968 +log0101 log 5.5344249034372126e+307 -1.2155859158431275e+308 -> 709.48562300345679 -1.143553056717973 +log0102 log -1.3155575403469408e+308 1.1610793541663864e+308 -> 709.75847809546428 2.41848796504974 +log0103 log -1.632366720973235e+308 -1.54299446211448e+308 -> 710.00545236515586 -2.3843326028455087 +log0104 log 0.0 5.9449276692327712e+307 -> 708.67616191258526 1.5707963267948966 +log0105 log -0.0 1.1201850459025692e+308 -> 709.30970253338171 1.5707963267948966 +log0106 log 0.0 -1.6214225933466528e+308 -> 709.6795125501086 -1.5707963267948966 +log0107 log -0.0 -1.7453269791591058e+308 -> 709.75315056087379 -1.5707963267948966 +log0108 log 1.440860577601428e+308 0.0 -> 709.56144920058262 0.0 +log0109 log 1.391515176148282e+308 -0.0 -> 709.52660185041327 -0.0 +log0110 log -1.201354401295296e+308 0.0 -> 709.37965823023956 3.1415926535897931 +log0111 log -1.6704337825976804e+308 -0.0 -> 709.70929198492399 -3.1415926535897931 +log0112 log 7.2276974655190223e+307 7.94879711369164 -> 708.87154406512104 1.0997689307850458e-307 +log0113 log 1.1207859593716076e+308 -6.1956200868221147 -> 709.31023883080104 -5.5279244310803286e-308 +log0114 log -4.6678933874471045e+307 9.947107893220382 -> 708.43433142431388 3.1415926535897931 +log0115 log -1.5108012453950142e+308 -5.3117197179375619 -> 709.60884877835008 -3.1415926535897931 +log0116 log 7.4903750871504435 1.5320703776626352e+308 -> 709.62282865085137 1.5707963267948966 +log0117 log 5.9760325525654778 -8.0149473997349123e+307 -> 708.97493177248396 -1.5707963267948966 +log0118 log -7.880194206386629 1.7861845814767441e+308 -> 709.77629046837137 1.5707963267948966 +log0119 log -9.886438993852865 -6.19235781080747e+307 -> 708.71693946977302 -1.5707963267948966 + +-- values near 0 +log0120 log 2.2996867579227779e-308 6.7861840770939125e-312 -> -708.36343567717392 0.00029509166223339815 +log0121 log 6.9169190417774516e-323 -9.0414013188948118e-322 -> -739.22766796468386 -1.4944423210001669 +log0122 log -1.5378064962914011e-316 1.8243628389354635e-310 -> -713.20014803142965 1.5707971697228842 +log0123 log -2.3319898483706837e-321 -2.2358763941866371e-313 -> -719.9045008332522 -1.570796337224766 +log0124 log 0.0 3.872770101081121e-315 -> -723.96033425374401 1.5707963267948966 +log0125 log -0.0 9.6342800939043076e-322 -> -739.16707236281752 1.5707963267948966 +log0126 log 0.0 -2.266099393427834e-308 -> -708.37814861757965 -1.5707963267948966 +log0127 log -0.0 -2.1184695673766626e-315 -> -724.56361036731812 -1.5707963267948966 +log0128 log 1.1363509854348671e-322 0.0 -> -741.30457770545206 0.0 +log0129 log 3.5572726500569751e-322 -0.0 -> -740.16340580236522 -0.0 +log0130 log -2.3696071074040593e-310 0.0 -> -712.93865466421641 3.1415926535897931 +log0131 log -2.813283897266934e-317 -0.0 -> -728.88512203138862 -3.1415926535897931 + +-- values near the unit circle +log0200 log -0.59999999999999998 0.80000000000000004 -> 2.2204460492503132e-17 2.2142974355881808 +log0201 log 0.79999999999999993 0.60000000000000009 -> 6.1629758220391547e-33 0.64350110879328448 + +-- special values +log1000 log -0.0 0.0 -> -inf 3.1415926535897931 divide-by-zero +log1001 log 0.0 0.0 -> -inf 0.0 divide-by-zero +log1002 log 0.0 inf -> inf 1.5707963267948966 +log1003 log 2.3 inf -> inf 1.5707963267948966 +log1004 log -0.0 inf -> inf 1.5707963267948966 +log1005 log -2.3 inf -> inf 1.5707963267948966 +log1006 log 0.0 nan -> nan nan +log1007 log 2.3 nan -> nan nan +log1008 log -0.0 nan -> nan nan +log1009 log -2.3 nan -> nan nan +log1010 log -inf 0.0 -> inf 3.1415926535897931 +log1011 log -inf 2.3 -> inf 3.1415926535897931 +log1012 log inf 0.0 -> inf 0.0 +log1013 log inf 2.3 -> inf 0.0 +log1014 log -inf inf -> inf 2.3561944901923448 +log1015 log inf inf -> inf 0.78539816339744828 +log1016 log inf nan -> inf nan +log1017 log -inf nan -> inf nan +log1018 log nan 0.0 -> nan nan +log1019 log nan 2.3 -> nan nan +log1020 log nan inf -> inf nan +log1021 log nan nan -> nan nan +log1022 log -0.0 -0.0 -> -inf -3.1415926535897931 divide-by-zero +log1023 log 0.0 -0.0 -> -inf -0.0 divide-by-zero +log1024 log 0.0 -inf -> inf -1.5707963267948966 +log1025 log 2.3 -inf -> inf -1.5707963267948966 +log1026 log -0.0 -inf -> inf -1.5707963267948966 +log1027 log -2.3 -inf -> inf -1.5707963267948966 +log1028 log -inf -0.0 -> inf -3.1415926535897931 +log1029 log -inf -2.3 -> inf -3.1415926535897931 +log1030 log inf -0.0 -> inf -0.0 +log1031 log inf -2.3 -> inf -0.0 +log1032 log -inf -inf -> inf -2.3561944901923448 +log1033 log inf -inf -> inf -0.78539816339744828 +log1034 log nan -0.0 -> nan nan +log1035 log nan -2.3 -> nan nan +log1036 log nan -inf -> inf nan + + +------------------------------ +-- log10: Logarithm base 10 -- +------------------------------ + +logt0000 log10 1.0 0.0 -> 0.0 0.0 +logt0001 log10 1.0 -0.0 -> 0.0 -0.0 +logt0002 log10 -1.0 0.0 -> 0.0 1.3643763538418414 +logt0003 log10 -1.0 -0.0 -> 0.0 -1.3643763538418414 +-- values along both sides of real axis +logt0010 log10 -9.8813129168249309e-324 0.0 -> -323.0051853474518 1.3643763538418414 +logt0011 log10 -9.8813129168249309e-324 -0.0 -> -323.0051853474518 -1.3643763538418414 +logt0012 log10 -1e-305 0.0 -> -305.0 1.3643763538418414 +logt0013 log10 -1e-305 -0.0 -> -305.0 -1.3643763538418414 +logt0014 log10 -1e-150 0.0 -> -150.0 1.3643763538418414 +logt0015 log10 -1e-150 -0.0 -> -150.0 -1.3643763538418414 +logt0016 log10 -9.9999999999999998e-17 0.0 -> -16.0 1.3643763538418414 +logt0017 log10 -9.9999999999999998e-17 -0.0 -> -16.0 -1.3643763538418414 +logt0018 log10 -0.001 0.0 -> -3.0 1.3643763538418414 +logt0019 log10 -0.001 -0.0 -> -3.0 -1.3643763538418414 +logt0020 log10 -0.57899999999999996 0.0 -> -0.23732143627256383 1.3643763538418414 +logt0021 log10 -0.57899999999999996 -0.0 -> -0.23732143627256383 -1.3643763538418414 +logt0022 log10 -0.99999999999999989 0.0 -> -4.821637332766436e-17 1.3643763538418414 +logt0023 log10 -0.99999999999999989 -0.0 -> -4.821637332766436e-17 -1.3643763538418414 +logt0024 log10 -1.0000000000000002 0.0 -> 9.6432746655328696e-17 1.3643763538418414 +logt0025 log10 -1.0000000000000002 -0.0 -> 9.6432746655328696e-17 -1.3643763538418414 +logt0026 log10 -1.0009999999999999 0.0 -> 0.0004340774793185929 1.3643763538418414 +logt0027 log10 -1.0009999999999999 -0.0 -> 0.0004340774793185929 -1.3643763538418414 +logt0028 log10 -2.0 0.0 -> 0.3010299956639812 1.3643763538418414 +logt0029 log10 -2.0 -0.0 -> 0.3010299956639812 -1.3643763538418414 +logt0030 log10 -23.0 0.0 -> 1.3617278360175928 1.3643763538418414 +logt0031 log10 -23.0 -0.0 -> 1.3617278360175928 -1.3643763538418414 +logt0032 log10 -10000000000000000.0 0.0 -> 16.0 1.3643763538418414 +logt0033 log10 -10000000000000000.0 -0.0 -> 16.0 -1.3643763538418414 +logt0034 log10 -9.9999999999999998e+149 0.0 -> 150.0 1.3643763538418414 +logt0035 log10 -9.9999999999999998e+149 -0.0 -> 150.0 -1.3643763538418414 +logt0036 log10 -1.0000000000000001e+299 0.0 -> 299.0 1.3643763538418414 +logt0037 log10 -1.0000000000000001e+299 -0.0 -> 299.0 -1.3643763538418414 +logt0038 log10 9.8813129168249309e-324 0.0 -> -323.0051853474518 0.0 +logt0039 log10 9.8813129168249309e-324 -0.0 -> -323.0051853474518 -0.0 +logt0040 log10 1e-305 0.0 -> -305.0 0.0 +logt0041 log10 1e-305 -0.0 -> -305.0 -0.0 +logt0042 log10 1e-150 0.0 -> -150.0 0.0 +logt0043 log10 1e-150 -0.0 -> -150.0 -0.0 +logt0044 log10 9.9999999999999998e-17 0.0 -> -16.0 0.0 +logt0045 log10 9.9999999999999998e-17 -0.0 -> -16.0 -0.0 +logt0046 log10 0.001 0.0 -> -3.0 0.0 +logt0047 log10 0.001 -0.0 -> -3.0 -0.0 +logt0048 log10 0.57899999999999996 0.0 -> -0.23732143627256383 0.0 +logt0049 log10 0.57899999999999996 -0.0 -> -0.23732143627256383 -0.0 +logt0050 log10 0.99999999999999989 0.0 -> -4.821637332766436e-17 0.0 +logt0051 log10 0.99999999999999989 -0.0 -> -4.821637332766436e-17 -0.0 +logt0052 log10 1.0000000000000002 0.0 -> 9.6432746655328696e-17 0.0 +logt0053 log10 1.0000000000000002 -0.0 -> 9.6432746655328696e-17 -0.0 +logt0054 log10 1.0009999999999999 0.0 -> 0.0004340774793185929 0.0 +logt0055 log10 1.0009999999999999 -0.0 -> 0.0004340774793185929 -0.0 +logt0056 log10 2.0 0.0 -> 0.3010299956639812 0.0 +logt0057 log10 2.0 -0.0 -> 0.3010299956639812 -0.0 +logt0058 log10 23.0 0.0 -> 1.3617278360175928 0.0 +logt0059 log10 23.0 -0.0 -> 1.3617278360175928 -0.0 +logt0060 log10 10000000000000000.0 0.0 -> 16.0 0.0 +logt0061 log10 10000000000000000.0 -0.0 -> 16.0 -0.0 +logt0062 log10 9.9999999999999998e+149 0.0 -> 150.0 0.0 +logt0063 log10 9.9999999999999998e+149 -0.0 -> 150.0 -0.0 +logt0064 log10 1.0000000000000001e+299 0.0 -> 299.0 0.0 +logt0065 log10 1.0000000000000001e+299 -0.0 -> 299.0 -0.0 + +-- random inputs +logt0066 log10 -1.9830454945186191e-16 -2.0334448025673346 -> 0.30823238806798503 -0.68218817692092071 +logt0067 log10 -0.96745853024741857 -0.84995816228299692 -> 0.10984528422284802 -1.051321426174086 +logt0068 log10 -0.1603644313948418 -0.2929942111041835 -> -0.47624115633305419 -0.89967884023059597 +logt0069 log10 -0.15917913168438699 -0.25238799251132177 -> -0.52521304641665956 -0.92655790645688119 +logt0070 log10 -0.68907818535078802 -3.0693105853476346 -> 0.4977187885066448 -0.77809953119328823 +logt0071 log10 -17.268133447565589 6.8165120014604756 -> 1.2686912008098534 1.2010954629104202 +logt0072 log10 -1.7153894479690328 26.434055372802636 -> 1.423076309032751 0.71033145859005309 +logt0073 log10 -8.0456794648936578e-06 0.19722758057570208 -> -0.70503235244987561 0.68220589348055516 +logt0074 log10 -2.4306442691323173 0.6846919750700996 -> 0.40230257845332595 1.2451292533748923 +logt0075 log10 -3.5488049250888194 0.45324040643185254 -> 0.55359553977141063 1.3092085108866405 +logt0076 log10 0.18418516851510189 -0.26062518836212617 -> -0.49602019732913638 -0.41500503556604301 +logt0077 log10 2.7124837795638399 -13.148769067133387 -> 1.1279348613317008 -0.59383616643803216 +logt0078 log10 3.6521275476169149e-13 -3.7820543023170673e-05 -> -4.4222722398941112 -0.68218817272717114 +logt0079 log10 5.0877545813862239 -1.2834978326786852 -> 0.71992371806426847 -0.10732104352159283 +logt0080 log10 0.26477986808461512 -0.67659001194187429 -> -0.13873139935281681 -0.52018649631300229 +logt0081 log10 0.0014754261398071962 5.3514691608205442 -> 0.72847304354528819 0.6820684398178033 +logt0082 log10 0.29667334462157885 0.00020056045042584795 -> -0.52772137299296806 0.00029359659442937261 +logt0083 log10 0.82104233671099425 3.9005387130133102 -> 0.60053889028349361 0.59208690021184018 +logt0084 log10 0.27268135358180667 124.42088110945804 -> 2.094894315538069 0.68123637673656989 +logt0085 log10 0.0026286959168267485 0.47795808180573013 -> -0.32060362226100814 0.67979964816877081 + +-- values near infinity +logt0100 log10 1.0512025744003172e+308 7.2621669750664611e+307 -> 308.10641562682065 0.26255461408256975 +logt0101 log10 5.5344249034372126e+307 -1.2155859158431275e+308 -> 308.12569106009209 -0.496638782296212 +logt0102 log10 -1.3155575403469408e+308 1.1610793541663864e+308 -> 308.24419052091019 1.0503359777705266 +logt0103 log10 -1.632366720973235e+308 -1.54299446211448e+308 -> 308.3514500834093 -1.0355024924378222 +logt0104 log10 0.0 5.9449276692327712e+307 -> 307.77414657501117 0.68218817692092071 +logt0105 log10 -0.0 1.1201850459025692e+308 -> 308.04928977068465 0.68218817692092071 +logt0106 log10 0.0 -1.6214225933466528e+308 -> 308.20989622030174 -0.68218817692092071 +logt0107 log10 -0.0 -1.7453269791591058e+308 -> 308.24187680203539 -0.68218817692092071 +logt0108 log10 1.440860577601428e+308 0.0 -> 308.15862195908755 0.0 +logt0109 log10 1.391515176148282e+308 -0.0 -> 308.14348794720007 -0.0 +logt0110 log10 -1.201354401295296e+308 0.0 -> 308.07967114380773 1.3643763538418414 +logt0111 log10 -1.6704337825976804e+308 -0.0 -> 308.22282926451624 -1.3643763538418414 +logt0112 log10 7.2276974655190223e+307 7.94879711369164 -> 307.85899996571993 4.7762357800858463e-308 +logt0113 log10 1.1207859593716076e+308 -6.1956200868221147 -> 308.04952268169455 -2.4007470767963597e-308 +logt0114 log10 -4.6678933874471045e+307 9.947107893220382 -> 307.66912092839902 1.3643763538418414 +logt0115 log10 -1.5108012453950142e+308 -5.3117197179375619 -> 308.1792073341565 -1.3643763538418414 +logt0116 log10 7.4903750871504435 1.5320703776626352e+308 -> 308.18527871564157 0.68218817692092071 +logt0117 log10 5.9760325525654778 -8.0149473997349123e+307 -> 307.90390067652424 -0.68218817692092071 +logt0118 log10 -7.880194206386629 1.7861845814767441e+308 -> 308.25192633617331 0.68218817692092071 +logt0119 log10 -9.886438993852865 -6.19235781080747e+307 -> 307.79185604308338 -0.68218817692092071 + +-- values near 0 +logt0120 log10 2.2996867579227779e-308 6.7861840770939125e-312 -> -307.63833129662572 0.00012815668056362305 +logt0121 log10 6.9169190417774516e-323 -9.0414013188948118e-322 -> -321.04249706727148 -0.64902805353306059 +logt0122 log10 -1.5378064962914011e-316 1.8243628389354635e-310 -> -309.73888878263222 0.68218854299989429 +logt0123 log10 -2.3319898483706837e-321 -2.2358763941866371e-313 -> -312.65055220919641 -0.68218818145055538 +logt0124 log10 0.0 3.872770101081121e-315 -> -314.41197828323476 0.68218817692092071 +logt0125 log10 -0.0 9.6342800939043076e-322 -> -321.01618073175331 0.68218817692092071 +logt0126 log10 0.0 -2.266099393427834e-308 -> -307.64472104545649 -0.68218817692092071 +logt0127 log10 -0.0 -2.1184695673766626e-315 -> -314.67397777042407 -0.68218817692092071 +logt0128 log10 1.1363509854348671e-322 0.0 -> -321.94448750709819 0.0 +logt0129 log10 3.5572726500569751e-322 -0.0 -> -321.44888284668451 -0.0 +logt0130 log10 -2.3696071074040593e-310 0.0 -> -309.62532365619722 1.3643763538418414 +logt0131 log10 -2.813283897266934e-317 -0.0 -> -316.55078643961042 -1.3643763538418414 + +-- values near the unit circle +logt0200 log10 -0.59999999999999998 0.80000000000000004 -> 9.6432746655328709e-18 0.96165715756846815 +logt0201 log10 0.79999999999999993 0.60000000000000009 -> 2.6765463916147622e-33 0.2794689806475476 + +-- special values +logt1000 log10 -0.0 0.0 -> -inf 1.3643763538418414 divide-by-zero +logt1001 log10 0.0 0.0 -> -inf 0.0 divide-by-zero +logt1002 log10 0.0 inf -> inf 0.68218817692092071 +logt1003 log10 2.3 inf -> inf 0.68218817692092071 +logt1004 log10 -0.0 inf -> inf 0.68218817692092071 +logt1005 log10 -2.3 inf -> inf 0.68218817692092071 +logt1006 log10 0.0 nan -> nan nan +logt1007 log10 2.3 nan -> nan nan +logt1008 log10 -0.0 nan -> nan nan +logt1009 log10 -2.3 nan -> nan nan +logt1010 log10 -inf 0.0 -> inf 1.3643763538418414 +logt1011 log10 -inf 2.3 -> inf 1.3643763538418414 +logt1012 log10 inf 0.0 -> inf 0.0 +logt1013 log10 inf 2.3 -> inf 0.0 +logt1014 log10 -inf inf -> inf 1.0232822653813811 +logt1015 log10 inf inf -> inf 0.34109408846046035 +logt1016 log10 inf nan -> inf nan +logt1017 log10 -inf nan -> inf nan +logt1018 log10 nan 0.0 -> nan nan +logt1019 log10 nan 2.3 -> nan nan +logt1020 log10 nan inf -> inf nan +logt1021 log10 nan nan -> nan nan +logt1022 log10 -0.0 -0.0 -> -inf -1.3643763538418414 divide-by-zero +logt1023 log10 0.0 -0.0 -> -inf -0.0 divide-by-zero +logt1024 log10 0.0 -inf -> inf -0.68218817692092071 +logt1025 log10 2.3 -inf -> inf -0.68218817692092071 +logt1026 log10 -0.0 -inf -> inf -0.68218817692092071 +logt1027 log10 -2.3 -inf -> inf -0.68218817692092071 +logt1028 log10 -inf -0.0 -> inf -1.3643763538418414 +logt1029 log10 -inf -2.3 -> inf -1.3643763538418414 +logt1030 log10 inf -0.0 -> inf -0.0 +logt1031 log10 inf -2.3 -> inf -0.0 +logt1032 log10 -inf -inf -> inf -1.0232822653813811 +logt1033 log10 inf -inf -> inf -0.34109408846046035 +logt1034 log10 nan -0.0 -> nan nan +logt1035 log10 nan -2.3 -> nan nan +logt1036 log10 nan -inf -> inf nan + + +----------------------- +-- sqrt: Square root -- +----------------------- + +-- zeros +sqrt0000 sqrt 0.0 0.0 -> 0.0 0.0 +sqrt0001 sqrt 0.0 -0.0 -> 0.0 -0.0 +sqrt0002 sqrt -0.0 0.0 -> 0.0 0.0 +sqrt0003 sqrt -0.0 -0.0 -> 0.0 -0.0 + +-- values along both sides of real axis +sqrt0010 sqrt -9.8813129168249309e-324 0.0 -> 0.0 3.1434555694052576e-162 +sqrt0011 sqrt -9.8813129168249309e-324 -0.0 -> 0.0 -3.1434555694052576e-162 +sqrt0012 sqrt -1e-305 0.0 -> 0.0 3.1622776601683791e-153 +sqrt0013 sqrt -1e-305 -0.0 -> 0.0 -3.1622776601683791e-153 +sqrt0014 sqrt -1e-150 0.0 -> 0.0 9.9999999999999996e-76 +sqrt0015 sqrt -1e-150 -0.0 -> 0.0 -9.9999999999999996e-76 +sqrt0016 sqrt -9.9999999999999998e-17 0.0 -> 0.0 1e-08 +sqrt0017 sqrt -9.9999999999999998e-17 -0.0 -> 0.0 -1e-08 +sqrt0018 sqrt -0.001 0.0 -> 0.0 0.031622776601683791 +sqrt0019 sqrt -0.001 -0.0 -> 0.0 -0.031622776601683791 +sqrt0020 sqrt -0.57899999999999996 0.0 -> 0.0 0.76092049518987193 +sqrt0021 sqrt -0.57899999999999996 -0.0 -> 0.0 -0.76092049518987193 +sqrt0022 sqrt -0.99999999999999989 0.0 -> 0.0 0.99999999999999989 +sqrt0023 sqrt -0.99999999999999989 -0.0 -> 0.0 -0.99999999999999989 +sqrt0024 sqrt -1.0000000000000002 0.0 -> 0.0 1.0 +sqrt0025 sqrt -1.0000000000000002 -0.0 -> 0.0 -1.0 +sqrt0026 sqrt -1.0009999999999999 0.0 -> 0.0 1.000499875062461 +sqrt0027 sqrt -1.0009999999999999 -0.0 -> 0.0 -1.000499875062461 +sqrt0028 sqrt -2.0 0.0 -> 0.0 1.4142135623730951 +sqrt0029 sqrt -2.0 -0.0 -> 0.0 -1.4142135623730951 +sqrt0030 sqrt -23.0 0.0 -> 0.0 4.7958315233127191 +sqrt0031 sqrt -23.0 -0.0 -> 0.0 -4.7958315233127191 +sqrt0032 sqrt -10000000000000000.0 0.0 -> 0.0 100000000.0 +sqrt0033 sqrt -10000000000000000.0 -0.0 -> 0.0 -100000000.0 +sqrt0034 sqrt -9.9999999999999998e+149 0.0 -> 0.0 9.9999999999999993e+74 +sqrt0035 sqrt -9.9999999999999998e+149 -0.0 -> 0.0 -9.9999999999999993e+74 +sqrt0036 sqrt -1.0000000000000001e+299 0.0 -> 0.0 3.1622776601683796e+149 +sqrt0037 sqrt -1.0000000000000001e+299 -0.0 -> 0.0 -3.1622776601683796e+149 +sqrt0038 sqrt 9.8813129168249309e-324 0.0 -> 3.1434555694052576e-162 0.0 +sqrt0039 sqrt 9.8813129168249309e-324 -0.0 -> 3.1434555694052576e-162 -0.0 +sqrt0040 sqrt 1e-305 0.0 -> 3.1622776601683791e-153 0.0 +sqrt0041 sqrt 1e-305 -0.0 -> 3.1622776601683791e-153 -0.0 +sqrt0042 sqrt 1e-150 0.0 -> 9.9999999999999996e-76 0.0 +sqrt0043 sqrt 1e-150 -0.0 -> 9.9999999999999996e-76 -0.0 +sqrt0044 sqrt 9.9999999999999998e-17 0.0 -> 1e-08 0.0 +sqrt0045 sqrt 9.9999999999999998e-17 -0.0 -> 1e-08 -0.0 +sqrt0046 sqrt 0.001 0.0 -> 0.031622776601683791 0.0 +sqrt0047 sqrt 0.001 -0.0 -> 0.031622776601683791 -0.0 +sqrt0048 sqrt 0.57899999999999996 0.0 -> 0.76092049518987193 0.0 +sqrt0049 sqrt 0.57899999999999996 -0.0 -> 0.76092049518987193 -0.0 +sqrt0050 sqrt 0.99999999999999989 0.0 -> 0.99999999999999989 0.0 +sqrt0051 sqrt 0.99999999999999989 -0.0 -> 0.99999999999999989 -0.0 +sqrt0052 sqrt 1.0000000000000002 0.0 -> 1.0 0.0 +sqrt0053 sqrt 1.0000000000000002 -0.0 -> 1.0 -0.0 +sqrt0054 sqrt 1.0009999999999999 0.0 -> 1.000499875062461 0.0 +sqrt0055 sqrt 1.0009999999999999 -0.0 -> 1.000499875062461 -0.0 +sqrt0056 sqrt 2.0 0.0 -> 1.4142135623730951 0.0 +sqrt0057 sqrt 2.0 -0.0 -> 1.4142135623730951 -0.0 +sqrt0058 sqrt 23.0 0.0 -> 4.7958315233127191 0.0 +sqrt0059 sqrt 23.0 -0.0 -> 4.7958315233127191 -0.0 +sqrt0060 sqrt 10000000000000000.0 0.0 -> 100000000.0 0.0 +sqrt0061 sqrt 10000000000000000.0 -0.0 -> 100000000.0 -0.0 +sqrt0062 sqrt 9.9999999999999998e+149 0.0 -> 9.9999999999999993e+74 0.0 +sqrt0063 sqrt 9.9999999999999998e+149 -0.0 -> 9.9999999999999993e+74 -0.0 +sqrt0064 sqrt 1.0000000000000001e+299 0.0 -> 3.1622776601683796e+149 0.0 +sqrt0065 sqrt 1.0000000000000001e+299 -0.0 -> 3.1622776601683796e+149 -0.0 + +-- random inputs +sqrt0100 sqrt -0.34252542541549913 -223039880.15076211 -> 10560.300180587592 -10560.300196805192 +sqrt0101 sqrt -0.88790791393018909 -5.3307751730827402 -> 1.5027154613689004 -1.7737140896343291 +sqrt0102 sqrt -113916.89291310767 -0.018143374626153858 -> 2.6877817875351178e-05 -337.51576691038952 +sqrt0103 sqrt -0.63187172386197121 -0.26293913366617694 -> 0.16205707495266153 -0.81125471918761971 +sqrt0104 sqrt -0.058185169308906215 -2.3548312990430991 -> 1.0717660342420072 -1.0985752598086966 +sqrt0105 sqrt -1.0580584765935896 0.14400319259151736 -> 0.069837489270111242 1.030987755262468 +sqrt0106 sqrt -1.1667595947504932 0.11159711473953678 -> 0.051598531319315251 1.0813981705111229 +sqrt0107 sqrt -0.5123728411449906 0.026175433648339085 -> 0.018278026262418718 0.71603556293597614 +sqrt0108 sqrt -3.7453400060067228 1.0946500314809635 -> 0.27990088541692498 1.9554243814742367 +sqrt0109 sqrt -0.0027736121575097673 1.0367943000839817 -> 0.71903560338719175 0.72096172651250545 +sqrt0110 sqrt 1501.2559699453188 -1.1997325207283589 -> 38.746047664730959 -0.015481998720355024 +sqrt0111 sqrt 1.4830075326850578 -0.64100878436755349 -> 1.244712815741096 -0.25749264258434584 +sqrt0112 sqrt 0.095395618499734602 -0.48226565701639595 -> 0.54175904053472879 -0.44509239434231551 +sqrt0113 sqrt 0.50109185681863277 -0.54054037379892561 -> 0.7868179858332387 -0.34349772344520979 +sqrt0114 sqrt 0.98779807595367897 -0.00019848758437225191 -> 0.99388031770665153 -9.9854872279921968e-05 +sqrt0115 sqrt 11.845472380792259 0.0010051104581506761 -> 3.4417252072345397 0.00014601840612346451 +sqrt0116 sqrt 2.3558249686735975 0.25605157371744403 -> 1.5371278477386647 0.083288964575761404 +sqrt0117 sqrt 0.77584894123159098 1.0496420627016076 -> 1.0200744386390885 0.51449287568756552 +sqrt0118 sqrt 1.8961715669604893 0.34940793467158854 -> 1.3827991781411615 0.12634080935066902 +sqrt0119 sqrt 0.96025378316565801 0.69573224860140515 -> 1.0358710342209998 0.33581991658093457 + +-- values near 0 +sqrt0120 sqrt 7.3577938365086866e-313 8.1181408465112743e-319 -> 8.5777583531543516e-157 4.732087634251168e-163 +sqrt0121 sqrt 1.2406883874892108e-310 -5.1210133324269776e-312 -> 1.1140990057468052e-155 -2.2982756945349973e-157 +sqrt0122 sqrt -7.1145453001139502e-322 2.9561379244703735e-314 -> 1.2157585807480286e-157 1.2157586100077242e-157 +sqrt0123 sqrt -4.9963244206801218e-314 -8.4718424423690227e-319 -> 1.8950582312540437e-162 -2.2352459419578971e-157 +sqrt0124 sqrt 0.0 7.699553609385195e-318 -> 1.9620848107797476e-159 1.9620848107797476e-159 +sqrt0125 sqrt -0.0 3.3900826606499415e-309 -> 4.1170879639922327e-155 4.1170879639922327e-155 +sqrt0126 sqrt 0.0 -9.8907989772250828e-319 -> 7.032353438652342e-160 -7.032353438652342e-160 +sqrt0127 sqrt -0.0 -1.3722939367590908e-315 -> 2.6194407196566702e-158 -2.6194407196566702e-158 +sqrt0128 sqrt 7.9050503334599447e-323 0.0 -> 8.8910349979403099e-162 0.0 +sqrt0129 sqrt 1.8623241768349486e-309 -0.0 -> 4.3154654173506579e-155 -0.0 +sqrt0130 sqrt -2.665971134499887e-308 0.0 -> 0.0 1.6327801856036491e-154 +sqrt0131 sqrt -1.5477066694467245e-310 -0.0 -> 0.0 -1.2440685951533077e-155 + +-- inputs whose absolute value overflows +sqrt0140 sqrt 1.6999999999999999e+308 -1.6999999999999999e+308 -> 1.4325088230154573e+154 -5.9336458271212207e+153 +sqrt0141 sqrt -1.797e+308 -9.9999999999999999e+306 -> 3.7284476432057307e+152 -1.3410406899802901e+154 + +-- special values +sqrt1000 sqrt 0.0 0.0 -> 0.0 0.0 +sqrt1001 sqrt -0.0 0.0 -> 0.0 0.0 +sqrt1002 sqrt 0.0 inf -> inf inf +sqrt1003 sqrt 2.3 inf -> inf inf +sqrt1004 sqrt inf inf -> inf inf +sqrt1005 sqrt -0.0 inf -> inf inf +sqrt1006 sqrt -2.3 inf -> inf inf +sqrt1007 sqrt -inf inf -> inf inf +sqrt1008 sqrt nan inf -> inf inf +sqrt1009 sqrt 0.0 nan -> nan nan +sqrt1010 sqrt 2.3 nan -> nan nan +sqrt1011 sqrt -0.0 nan -> nan nan +sqrt1012 sqrt -2.3 nan -> nan nan +sqrt1013 sqrt -inf 0.0 -> 0.0 inf +sqrt1014 sqrt -inf 2.3 -> 0.0 inf +sqrt1015 sqrt inf 0.0 -> inf 0.0 +sqrt1016 sqrt inf 2.3 -> inf 0.0 +sqrt1017 sqrt -inf nan -> nan inf ignore-imag-sign +sqrt1018 sqrt inf nan -> inf nan +sqrt1019 sqrt nan 0.0 -> nan nan +sqrt1020 sqrt nan 2.3 -> nan nan +sqrt1021 sqrt nan nan -> nan nan +sqrt1022 sqrt 0.0 -0.0 -> 0.0 -0.0 +sqrt1023 sqrt -0.0 -0.0 -> 0.0 -0.0 +sqrt1024 sqrt 0.0 -inf -> inf -inf +sqrt1025 sqrt 2.3 -inf -> inf -inf +sqrt1026 sqrt inf -inf -> inf -inf +sqrt1027 sqrt -0.0 -inf -> inf -inf +sqrt1028 sqrt -2.3 -inf -> inf -inf +sqrt1029 sqrt -inf -inf -> inf -inf +sqrt1030 sqrt nan -inf -> inf -inf +sqrt1031 sqrt -inf -0.0 -> 0.0 -inf +sqrt1032 sqrt -inf -2.3 -> 0.0 -inf +sqrt1033 sqrt inf -0.0 -> inf -0.0 +sqrt1034 sqrt inf -2.3 -> inf -0.0 +sqrt1035 sqrt nan -0.0 -> nan nan +sqrt1036 sqrt nan -2.3 -> nan nan + + +-- For exp, cosh, sinh, tanh we limit tests to arguments whose +-- imaginary part is less than 10 in absolute value: most math +-- libraries have poor accuracy for (real) sine and cosine for +-- large arguments, and the accuracy of these complex functions +-- suffer correspondingly. +-- +-- Similarly, for cos, sin and tan we limit tests to arguments +-- with relatively small real part. + + +------------------------------- +-- exp: Exponential function -- +------------------------------- + +-- zeros +exp0000 exp 0.0 0.0 -> 1.0 0.0 +exp0001 exp 0.0 -0.0 -> 1.0 -0.0 +exp0002 exp -0.0 0.0 -> 1.0 0.0 +exp0003 exp -0.0 -0.0 -> 1.0 -0.0 + +-- random inputs +exp0004 exp -17.957359009564684 -1.108613895795274 -> 7.0869292576226611e-09 -1.4225929202377833e-08 +exp0005 exp -1.4456149663368642e-15 -0.75359817331772239 -> 0.72923148323917997 -0.68426708517419033 +exp0006 exp -0.76008654883512661 -0.46657235480105019 -> 0.41764393109928666 -0.21035108396792854 +exp0007 exp -5.7071614697735731 -2.3744161818115816e-11 -> 0.0033220890242068356 -7.8880219364953578e-14 +exp0008 exp -0.4653981327927097 -5.2236706667445587e-21 -> 0.62788507378216663 -3.2798648420026468e-21 +exp0009 exp -3.2444565242295518 1.1535625304243959 -> 0.015799936931457641 0.035644950380024749 +exp0010 exp -3.0651456337977727 0.87765086532391878 -> 0.029805595629855953 0.035882775180855669 +exp0011 exp -0.11080823753233926 0.96486386300873106 -> 0.50979112534376314 0.73575512419561562 +exp0012 exp -2.5629722598928648 0.019636235754708079 -> 0.077060452853917397 0.0015133717341137684 +exp0013 exp -3.3201709957983357e-10 1.2684017344487268 -> 0.29780699855434889 0.95462610007689186 +exp0014 exp 0.88767276057993272 -0.18953422986895557 -> 2.3859624049858095 -0.45771559132044426 +exp0015 exp 1.5738333486794742 -2.2576803075544328e-11 -> 4.8251091132458654 -1.0893553826776623e-10 +exp0016 exp 1.6408702341813795 -1.438879484380837 -> 0.6786733590689048 -5.1148284173168825 +exp0017 exp 1.820279424202033 -0.020812040370785722 -> 6.1722462896420902 -0.1284755888435051 +exp0018 exp 1.7273965735945873 -0.61140621328954947 -> 4.6067931898799976 -3.2294267694441308 +exp0019 exp 2.5606034306862995 0.098153136008435504 -> 12.881325889966629 1.2684184812864494 +exp0020 exp 10.280368619483029 3.4564622559748535 -> -27721.283321551502 -9028.9663215568835 +exp0021 exp 1.104007405129741e-155 0.21258803067317278 -> 0.97748813933531764 0.21099037290544478 +exp0022 exp 0.027364777809295172 0.00059226603500623363 -> 1.0277424518451876 0.0006086970181346579 +exp0023 exp 0.94356313429255245 3.418530463518592 -> -2.4712285695346194 -0.70242654900218349 + +-- cases where exp(z) representable, exp(z.real) not +exp0030 exp 710.0 0.78500000000000003 -> 1.5803016909637158e+308 1.5790437551806911e+308 +exp0031 exp 710.0 -0.78500000000000003 -> 1.5803016909637158e+308 -1.5790437551806911e+308 + +-- values for which exp(x) is subnormal, or underflows to 0 +exp0040 exp -735.0 0.78500000000000003 -> 4.3976783136329355e-320 4.3942198541120468e-320 +exp0041 exp -735.0 -2.3559999999999999 -> -4.3952079854037293e-320 -4.396690182341253e-320 +exp0042 exp -745.0 0.0 -> 4.9406564584124654e-324 0.0 +exp0043 exp -745.0 0.7 -> 0.0 0.0 +exp0044 exp -745.0 2.1 -> -0.0 0.0 +exp0045 exp -745.0 3.7 -> -0.0 -0.0 +exp0046 exp -745.0 5.3 -> 0.0 -0.0 + +-- values for which exp(z) overflows +exp0050 exp 710.0 0.0 -> inf 0.0 overflow +exp0051 exp 711.0 0.7 -> inf inf overflow +exp0052 exp 710.0 1.5 -> 1.5802653829857376e+307 inf overflow +exp0053 exp 710.0 1.6 -> -6.5231579995501372e+306 inf overflow +exp0054 exp 710.0 2.8 -> -inf 7.4836177417448528e+307 overflow + +-- special values +exp1000 exp 0.0 0.0 -> 1.0 0.0 +exp1001 exp -0.0 0.0 -> 1.0 0.0 +exp1002 exp 0.0 inf -> nan nan invalid +exp1003 exp 2.3 inf -> nan nan invalid +exp1004 exp -0.0 inf -> nan nan invalid +exp1005 exp -2.3 inf -> nan nan invalid +exp1006 exp 0.0 nan -> nan nan +exp1007 exp 2.3 nan -> nan nan +exp1008 exp -0.0 nan -> nan nan +exp1009 exp -2.3 nan -> nan nan +exp1010 exp -inf 0.0 -> 0.0 0.0 +exp1011 exp -inf 1.4 -> 0.0 0.0 +exp1012 exp -inf 2.8 -> -0.0 0.0 +exp1013 exp -inf 4.2 -> -0.0 -0.0 +exp1014 exp -inf 5.6 -> 0.0 -0.0 +exp1015 exp -inf 7.0 -> 0.0 0.0 +exp1016 exp inf 0.0 -> inf 0.0 +exp1017 exp inf 1.4 -> inf inf +exp1018 exp inf 2.8 -> -inf inf +exp1019 exp inf 4.2 -> -inf -inf +exp1020 exp inf 5.6 -> inf -inf +exp1021 exp inf 7.0 -> inf inf +exp1022 exp -inf inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +exp1023 exp inf inf -> inf nan invalid ignore-real-sign +exp1024 exp -inf nan -> 0.0 0.0 ignore-real-sign ignore-imag-sign +exp1025 exp inf nan -> inf nan ignore-real-sign +exp1026 exp nan 0.0 -> nan 0.0 +exp1027 exp nan 2.3 -> nan nan +exp1028 exp nan inf -> nan nan +exp1029 exp nan nan -> nan nan +exp1030 exp 0.0 -0.0 -> 1.0 -0.0 +exp1031 exp -0.0 -0.0 -> 1.0 -0.0 +exp1032 exp 0.0 -inf -> nan nan invalid +exp1033 exp 2.3 -inf -> nan nan invalid +exp1034 exp -0.0 -inf -> nan nan invalid +exp1035 exp -2.3 -inf -> nan nan invalid +exp1036 exp -inf -0.0 -> 0.0 -0.0 +exp1037 exp -inf -1.4 -> 0.0 -0.0 +exp1038 exp -inf -2.8 -> -0.0 -0.0 +exp1039 exp -inf -4.2 -> -0.0 0.0 +exp1040 exp -inf -5.6 -> 0.0 0.0 +exp1041 exp -inf -7.0 -> 0.0 -0.0 +exp1042 exp inf -0.0 -> inf -0.0 +exp1043 exp inf -1.4 -> inf -inf +exp1044 exp inf -2.8 -> -inf -inf +exp1045 exp inf -4.2 -> -inf inf +exp1046 exp inf -5.6 -> inf inf +exp1047 exp inf -7.0 -> inf -inf +exp1048 exp -inf -inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +exp1049 exp inf -inf -> inf nan invalid ignore-real-sign +exp1050 exp nan -0.0 -> nan -0.0 +exp1051 exp nan -2.3 -> nan nan +exp1052 exp nan -inf -> nan nan + + +----------------------------- +-- cosh: Hyperbolic Cosine -- +----------------------------- + +-- zeros +cosh0000 cosh 0.0 0.0 -> 1.0 0.0 +cosh0001 cosh 0.0 -0.0 -> 1.0 -0.0 +cosh0002 cosh -0.0 0.0 -> 1.0 -0.0 +cosh0003 cosh -0.0 -0.0 -> 1.0 0.0 + +-- random inputs +cosh0004 cosh -0.85395264297414253 -8.8553756148671958 -> -1.1684340348021185 0.51842195359787435 +cosh0005 cosh -19.584904237211223 -0.066582627994906177 -> 159816812.23336992 10656776.050406246 +cosh0006 cosh -0.11072618401130772 -1.484820215073247 -> 0.086397164744949503 0.11054275637717284 +cosh0007 cosh -3.4764840250681752 -0.48440348288275276 -> 14.325931955190844 7.5242053548737955 +cosh0008 cosh -0.52047063604524602 -0.3603805382775585 -> 1.0653940354683802 0.19193293606252473 +cosh0009 cosh -1.39518962975995 0.0074738604700702906 -> 2.1417031027235969 -0.01415518712296308 +cosh0010 cosh -0.37107064757653541 0.14728085307856609 -> 1.0580601496776991 -0.055712531964568587 +cosh0011 cosh -5.8470200958739653 4.0021722388336292 -> -112.86220667618285 131.24734033545013 +cosh0012 cosh -0.1700261444851883 0.97167540135354513 -> 0.57208748253577946 -0.1410904820240203 +cosh0013 cosh -0.44042397902648783 1.0904791964139742 -> 0.50760322393058133 -0.40333966652010816 +cosh0014 cosh 0.052267552491867299 -3.8889011430644174 -> -0.73452303414639297 0.035540704833537134 +cosh0015 cosh 0.98000764177127453 -1.2548829247784097 -> 0.47220747341416142 -1.0879421432180316 +cosh0016 cosh 0.083594701222644008 -0.88847899930181284 -> 0.63279782419312613 -0.064954566816002285 +cosh0017 cosh 1.38173531783776 -0.43185040816732229 -> 1.9221663374671647 -0.78073830858849347 +cosh0018 cosh 0.57315681120148465 -0.22255760951027942 -> 1.1399733125173004 -0.1335512343605956 +cosh0019 cosh 1.8882512333062347 4.5024932182383797 -> -0.7041602065362691 -3.1573822131964615 +cosh0020 cosh 0.5618219206858317 0.92620452129575348 -> 0.69822380405378381 0.47309067471054522 +cosh0021 cosh 0.54361442847062591 0.64176483583018462 -> 0.92234462074193491 0.34167906495845501 +cosh0022 cosh 0.0014777403107920331 1.3682028122677661 -> 0.2012106963899549 0.001447518137863219 +cosh0023 cosh 2.218885944363501 2.0015727395883687 -> -1.94294321081968 4.1290269176083196 + +-- large real part +cosh0030 cosh 710.5 2.3519999999999999 -> -1.2967465239355998e+308 1.3076707908857333e+308 +cosh0031 cosh -710.5 0.69999999999999996 -> 1.4085466381392499e+308 -1.1864024666450239e+308 + +-- special values +cosh1000 cosh 0.0 0.0 -> 1.0 0.0 +cosh1001 cosh 0.0 inf -> nan 0.0 invalid ignore-imag-sign +cosh1002 cosh 0.0 nan -> nan 0.0 ignore-imag-sign +cosh1003 cosh 2.3 inf -> nan nan invalid +cosh1004 cosh 2.3 nan -> nan nan +cosh1005 cosh inf 0.0 -> inf 0.0 +cosh1006 cosh inf 1.4 -> inf inf +cosh1007 cosh inf 2.8 -> -inf inf +cosh1008 cosh inf 4.2 -> -inf -inf +cosh1009 cosh inf 5.6 -> inf -inf +cosh1010 cosh inf 7.0 -> inf inf +cosh1011 cosh inf inf -> inf nan invalid ignore-real-sign +cosh1012 cosh inf nan -> inf nan +cosh1013 cosh nan 0.0 -> nan 0.0 ignore-imag-sign +cosh1014 cosh nan 2.3 -> nan nan +cosh1015 cosh nan inf -> nan nan +cosh1016 cosh nan nan -> nan nan +cosh1017 cosh 0.0 -0.0 -> 1.0 -0.0 +cosh1018 cosh 0.0 -inf -> nan 0.0 invalid ignore-imag-sign +cosh1019 cosh 2.3 -inf -> nan nan invalid +cosh1020 cosh inf -0.0 -> inf -0.0 +cosh1021 cosh inf -1.4 -> inf -inf +cosh1022 cosh inf -2.8 -> -inf -inf +cosh1023 cosh inf -4.2 -> -inf inf +cosh1024 cosh inf -5.6 -> inf inf +cosh1025 cosh inf -7.0 -> inf -inf +cosh1026 cosh inf -inf -> inf nan invalid ignore-real-sign +cosh1027 cosh nan -0.0 -> nan 0.0 ignore-imag-sign +cosh1028 cosh nan -2.3 -> nan nan +cosh1029 cosh nan -inf -> nan nan +cosh1030 cosh -0.0 -0.0 -> 1.0 0.0 +cosh1031 cosh -0.0 -inf -> nan 0.0 invalid ignore-imag-sign +cosh1032 cosh -0.0 nan -> nan 0.0 ignore-imag-sign +cosh1033 cosh -2.3 -inf -> nan nan invalid +cosh1034 cosh -2.3 nan -> nan nan +cosh1035 cosh -inf -0.0 -> inf 0.0 +cosh1036 cosh -inf -1.4 -> inf inf +cosh1037 cosh -inf -2.8 -> -inf inf +cosh1038 cosh -inf -4.2 -> -inf -inf +cosh1039 cosh -inf -5.6 -> inf -inf +cosh1040 cosh -inf -7.0 -> inf inf +cosh1041 cosh -inf -inf -> inf nan invalid ignore-real-sign +cosh1042 cosh -inf nan -> inf nan +cosh1043 cosh -0.0 0.0 -> 1.0 -0.0 +cosh1044 cosh -0.0 inf -> nan 0.0 invalid ignore-imag-sign +cosh1045 cosh -2.3 inf -> nan nan invalid +cosh1046 cosh -inf 0.0 -> inf -0.0 +cosh1047 cosh -inf 1.4 -> inf -inf +cosh1048 cosh -inf 2.8 -> -inf -inf +cosh1049 cosh -inf 4.2 -> -inf inf +cosh1050 cosh -inf 5.6 -> inf inf +cosh1051 cosh -inf 7.0 -> inf -inf +cosh1052 cosh -inf inf -> inf nan invalid ignore-real-sign + + +--------------------------- +-- sinh: Hyperbolic Sine -- +--------------------------- + +-- zeros +sinh0000 sinh 0.0 0.0 -> 0.0 0.0 +sinh0001 sinh 0.0 -0.0 -> 0.0 -0.0 +sinh0002 sinh -0.0 0.0 -> -0.0 0.0 +sinh0003 sinh -0.0 -0.0 -> -0.0 -0.0 + +-- random inputs +sinh0004 sinh -17.282588091462742 -0.38187948694103546 -> -14867386.857248396 -5970648.6553516639 +sinh0005 sinh -343.91971203143208 -5.0172868877771525e-22 -> -1.1518691776521735e+149 -5.7792581214689021e+127 +sinh0006 sinh -14.178122253300922 -1.9387157579351293 -> 258440.37909034826 -670452.58500946441 +sinh0007 sinh -1.0343810581686239 -1.0970235266369905 -> -0.56070858278092739 -1.4098883258046697 +sinh0008 sinh -0.066126561416368204 -0.070461584169961872 -> -0.066010558700938124 -0.070557276738637542 +sinh0009 sinh -0.37630149150308484 3.3621734692162173 -> 0.37591118119332617 -0.23447115926369383 +sinh0010 sinh -0.049941960978670055 0.40323767020414625 -> -0.045955482136329009 0.3928878494430646 +sinh0011 sinh -16.647852603903715 0.0026852219129082098 -> -8492566.5739382561 22804.480671133562 +sinh0012 sinh -1.476625314303694 0.89473773116683386 -> -1.2982943334382224 1.7966593367791204 +sinh0013 sinh -422.36429577556913 0.10366634502307912 -> -1.3400321008920044e+183 1.3941600948045599e+182 +sinh0014 sinh 0.09108340745641981 -0.40408227416070353 -> 0.083863724802237902 -0.39480716553935602 +sinh0015 sinh 2.036064132067386 -2.6831729961386239 -> -3.37621124363175 -1.723868330002817 +sinh0016 sinh 2.5616717223063317 -0.0078978498622717767 -> 6.4399415853815869 -0.051472264400722133 +sinh0017 sinh 0.336804011985188 -6.5654622971649337 -> 0.32962499307574578 -0.29449170159995197 +sinh0018 sinh 0.23774603755649693 -0.92467195799232049 -> 0.14449839490603389 -0.82109449053556793 +sinh0019 sinh 0.0011388273541465494 1.9676196882949855 -> -0.00044014605389634999 0.92229398407098806 +sinh0020 sinh 3.2443870105663759 0.8054287559616895 -> 8.8702890778527426 9.2610748597042196 +sinh0021 sinh 0.040628908857054738 0.098206391190944958 -> 0.04044426841671233 0.098129544739707392 +sinh0022 sinh 4.7252283918217696e-30 9.1198155642656697 -> -4.5071980561644404e-30 0.30025730701661713 +sinh0023 sinh 0.043713693678420068 0.22512549887532657 -> 0.042624198673416713 0.22344201231217961 + +-- large real part +sinh0030 sinh 710.5 -2.3999999999999999 -> -1.3579970564885919e+308 -1.24394470907798e+308 +sinh0031 sinh -710.5 0.80000000000000004 -> -1.2830671601735164e+308 1.3210954193997678e+308 + +-- special values +sinh1000 sinh 0.0 0.0 -> 0.0 0.0 +sinh1001 sinh 0.0 inf -> 0.0 nan invalid ignore-real-sign +sinh1002 sinh 0.0 nan -> 0.0 nan ignore-real-sign +sinh1003 sinh 2.3 inf -> nan nan invalid +sinh1004 sinh 2.3 nan -> nan nan +sinh1005 sinh inf 0.0 -> inf 0.0 +sinh1006 sinh inf 1.4 -> inf inf +sinh1007 sinh inf 2.8 -> -inf inf +sinh1008 sinh inf 4.2 -> -inf -inf +sinh1009 sinh inf 5.6 -> inf -inf +sinh1010 sinh inf 7.0 -> inf inf +sinh1011 sinh inf inf -> inf nan invalid ignore-real-sign +sinh1012 sinh inf nan -> inf nan ignore-real-sign +sinh1013 sinh nan 0.0 -> nan 0.0 +sinh1014 sinh nan 2.3 -> nan nan +sinh1015 sinh nan inf -> nan nan +sinh1016 sinh nan nan -> nan nan +sinh1017 sinh 0.0 -0.0 -> 0.0 -0.0 +sinh1018 sinh 0.0 -inf -> 0.0 nan invalid ignore-real-sign +sinh1019 sinh 2.3 -inf -> nan nan invalid +sinh1020 sinh inf -0.0 -> inf -0.0 +sinh1021 sinh inf -1.4 -> inf -inf +sinh1022 sinh inf -2.8 -> -inf -inf +sinh1023 sinh inf -4.2 -> -inf inf +sinh1024 sinh inf -5.6 -> inf inf +sinh1025 sinh inf -7.0 -> inf -inf +sinh1026 sinh inf -inf -> inf nan invalid ignore-real-sign +sinh1027 sinh nan -0.0 -> nan -0.0 +sinh1028 sinh nan -2.3 -> nan nan +sinh1029 sinh nan -inf -> nan nan +sinh1030 sinh -0.0 -0.0 -> -0.0 -0.0 +sinh1031 sinh -0.0 -inf -> 0.0 nan invalid ignore-real-sign +sinh1032 sinh -0.0 nan -> 0.0 nan ignore-real-sign +sinh1033 sinh -2.3 -inf -> nan nan invalid +sinh1034 sinh -2.3 nan -> nan nan +sinh1035 sinh -inf -0.0 -> -inf -0.0 +sinh1036 sinh -inf -1.4 -> -inf -inf +sinh1037 sinh -inf -2.8 -> inf -inf +sinh1038 sinh -inf -4.2 -> inf inf +sinh1039 sinh -inf -5.6 -> -inf inf +sinh1040 sinh -inf -7.0 -> -inf -inf +sinh1041 sinh -inf -inf -> inf nan invalid ignore-real-sign +sinh1042 sinh -inf nan -> inf nan ignore-real-sign +sinh1043 sinh -0.0 0.0 -> -0.0 0.0 +sinh1044 sinh -0.0 inf -> 0.0 nan invalid ignore-real-sign +sinh1045 sinh -2.3 inf -> nan nan invalid +sinh1046 sinh -inf 0.0 -> -inf 0.0 +sinh1047 sinh -inf 1.4 -> -inf inf +sinh1048 sinh -inf 2.8 -> inf inf +sinh1049 sinh -inf 4.2 -> inf -inf +sinh1050 sinh -inf 5.6 -> -inf -inf +sinh1051 sinh -inf 7.0 -> -inf inf +sinh1052 sinh -inf inf -> inf nan invalid ignore-real-sign + + +------------------------------ +-- tanh: Hyperbolic Tangent -- +------------------------------ + +-- zeros +tanh0000 tanh 0.0 0.0 -> 0.0 0.0 +tanh0001 tanh 0.0 -0.0 -> 0.0 -0.0 +tanh0002 tanh -0.0 0.0 -> -0.0 0.0 +tanh0003 tanh -0.0 -0.0 -> -0.0 -0.0 + +-- random inputs +tanh0004 tanh -21.200500450664993 -1.6970729480342996 -> -1.0 1.9241352344849399e-19 +tanh0005 tanh -0.34158771504251928 -8.0848504951747131 -> -2.123711225855613 1.2827526782026006 +tanh0006 tanh -15.454144725193689 -0.23619582288265617 -> -0.99999999999993283 -3.4336684248260036e-14 +tanh0007 tanh -7.6103163119661952 -0.7802748320307008 -> -0.99999999497219438 -4.9064845343755437e-07 +tanh0008 tanh -0.15374717235792129 -0.6351086327306138 -> -0.23246081703561869 -0.71083467433910219 +tanh0009 tanh -0.49101115474392465 0.09723001264886301 -> -0.45844445715492133 0.077191158541805888 +tanh0010 tanh -0.10690612157664491 2.861612800856395 -> -0.11519761626257358 -0.28400488355647507 +tanh0011 tanh -0.91505774192066702 1.5431174597727007 -> -1.381109893068114 0.025160819663709356 +tanh0012 tanh -0.057433367093792223 0.35491159541246459 -> -0.065220499046696953 0.36921788332369498 +tanh0013 tanh -1.3540418621233514 0.18969415642242535 -> -0.88235642861151387 0.043764069984411721 +tanh0014 tanh 0.94864783961003529 -0.11333689578867717 -> 0.74348401861861368 -0.051271042543855221 +tanh0015 tanh 1.9591698133845488 -0.0029654444904578339 -> 0.9610270776968135 -0.00022664240049212933 +tanh0016 tanh 1.0949715796669197 -0.24706642853984456 -> 0.81636574501369386 -0.087767436914149954 +tanh0017 tanh 5770428.2113731047 -3.7160580339833165 -> 1.0 -0.0 +tanh0018 tanh 1.5576782321399629 -1.0357943787966468 -> 1.0403002384895388 -0.081126347894671463 +tanh0019 tanh 0.62378536230552961 2.3471393579560216 -> 0.85582499238960363 -0.53569473646842869 +tanh0020 tanh 17.400628602508025 9.3987059533841979 -> 0.99999999999999845 -8.0175867720530832e-17 +tanh0021 tanh 0.15026177509871896 0.50630349159505472 -> 0.19367536571827768 0.53849847858853661 +tanh0022 tanh 0.57433977530711167 1.0071604546265627 -> 1.0857848159262844 0.69139213955872214 +tanh0023 tanh 0.16291181500449456 0.006972810241567544 -> 0.16149335907551157 0.0067910772903467817 + +-- large real part +tanh0030 tanh 710 0.13 -> 1.0 0.0 +tanh0031 tanh -711 7.4000000000000004 -> -1.0 0.0 +tanh0032 tanh 1000 -2.3199999999999998 -> 1.0 0.0 +tanh0033 tanh -1.0000000000000001e+300 -9.6699999999999999 -> -1.0 -0.0 + +--special values +tanh1000 tanh 0.0 0.0 -> 0.0 0.0 +tanh1001 tanh 0.0 inf -> nan nan invalid +tanh1002 tanh 2.3 inf -> nan nan invalid +tanh1003 tanh 0.0 nan -> nan nan +tanh1004 tanh 2.3 nan -> nan nan +tanh1005 tanh inf 0.0 -> 1.0 0.0 +tanh1006 tanh inf 0.7 -> 1.0 0.0 +tanh1007 tanh inf 1.4 -> 1.0 0.0 +tanh1008 tanh inf 2.1 -> 1.0 -0.0 +tanh1009 tanh inf 2.8 -> 1.0 -0.0 +tanh1010 tanh inf 3.5 -> 1.0 0.0 +tanh1011 tanh inf inf -> 1.0 0.0 ignore-imag-sign +tanh1012 tanh inf nan -> 1.0 0.0 ignore-imag-sign +tanh1013 tanh nan 0.0 -> nan 0.0 +tanh1014 tanh nan 2.3 -> nan nan +tanh1015 tanh nan inf -> nan nan +tanh1016 tanh nan nan -> nan nan +tanh1017 tanh 0.0 -0.0 -> 0.0 -0.0 +tanh1018 tanh 0.0 -inf -> nan nan invalid +tanh1019 tanh 2.3 -inf -> nan nan invalid +tanh1020 tanh inf -0.0 -> 1.0 -0.0 +tanh1021 tanh inf -0.7 -> 1.0 -0.0 +tanh1022 tanh inf -1.4 -> 1.0 -0.0 +tanh1023 tanh inf -2.1 -> 1.0 0.0 +tanh1024 tanh inf -2.8 -> 1.0 0.0 +tanh1025 tanh inf -3.5 -> 1.0 -0.0 +tanh1026 tanh inf -inf -> 1.0 0.0 ignore-imag-sign +tanh1027 tanh nan -0.0 -> nan -0.0 +tanh1028 tanh nan -2.3 -> nan nan +tanh1029 tanh nan -inf -> nan nan +tanh1030 tanh -0.0 -0.0 -> -0.0 -0.0 +tanh1031 tanh -0.0 -inf -> nan nan invalid +tanh1032 tanh -2.3 -inf -> nan nan invalid +tanh1033 tanh -0.0 nan -> nan nan +tanh1034 tanh -2.3 nan -> nan nan +tanh1035 tanh -inf -0.0 -> -1.0 -0.0 +tanh1036 tanh -inf -0.7 -> -1.0 -0.0 +tanh1037 tanh -inf -1.4 -> -1.0 -0.0 +tanh1038 tanh -inf -2.1 -> -1.0 0.0 +tanh1039 tanh -inf -2.8 -> -1.0 0.0 +tanh1040 tanh -inf -3.5 -> -1.0 -0.0 +tanh1041 tanh -inf -inf -> -1.0 0.0 ignore-imag-sign +tanh1042 tanh -inf nan -> -1.0 0.0 ignore-imag-sign +tanh1043 tanh -0.0 0.0 -> -0.0 0.0 +tanh1044 tanh -0.0 inf -> nan nan invalid +tanh1045 tanh -2.3 inf -> nan nan invalid +tanh1046 tanh -inf 0.0 -> -1.0 0.0 +tanh1047 tanh -inf 0.7 -> -1.0 0.0 +tanh1048 tanh -inf 1.4 -> -1.0 0.0 +tanh1049 tanh -inf 2.1 -> -1.0 -0.0 +tanh1050 tanh -inf 2.8 -> -1.0 -0.0 +tanh1051 tanh -inf 3.5 -> -1.0 0.0 +tanh1052 tanh -inf inf -> -1.0 0.0 ignore-imag-sign + + +----------------- +-- cos: Cosine -- +----------------- + +-- zeros +cos0000 cos 0.0 0.0 -> 1.0 -0.0 +cos0001 cos 0.0 -0.0 -> 1.0 0.0 +cos0002 cos -0.0 0.0 -> 1.0 0.0 +cos0003 cos -0.0 -0.0 -> 1.0 -0.0 + +-- random inputs +cos0004 cos -2.0689194692073034 -0.0016802181751734313 -> -0.47777827208561469 -0.0014760401501695971 +cos0005 cos -0.4209627318177977 -1.8238516774258027 -> 2.9010402201444108 -1.2329207042329617 +cos0006 cos -1.9402181630694557 -2.9751857392891217 -> -3.5465459297970985 -9.1119163586282248 +cos0007 cos -3.3118320290191616 -0.87871302909286142 -> -1.3911528636565498 0.16878141517391701 +cos0008 cos -4.9540404623376872 -0.57949232239026827 -> 0.28062445586552065 0.59467861308508008 +cos0009 cos -0.45374584316245026 1.3950283448373935 -> 1.9247665574290578 0.83004572204761107 +cos0010 cos -0.42578172040176843 1.2715881615413049 -> 1.7517161459489148 0.67863902697363332 +cos0011 cos -0.13862985354300136 0.43587635877670328 -> 1.0859880290361912 0.062157548146672272 +cos0012 cos -0.11073221308966584 9.9384082307326475e-15 -> 0.99387545040722947 1.0982543264065479e-15 +cos0013 cos -1.5027633662054623e-07 0.0069668060249955498 -> 1.0000242682912412 1.0469545565660995e-09 +cos0014 cos 4.9728645490503052 -0.00027479808860952822 -> 0.25754011731975501 -0.00026552849549083186 +cos0015 cos 7.81969303486719 -0.79621523445878783 -> 0.045734882501585063 0.88253139933082991 +cos0016 cos 0.13272421880766716 -0.74668445308718201 -> 1.2806012244432847 0.10825373267437005 +cos0017 cos 4.2396521985973274 -2.2178848380884881 -> -2.1165117057056855 -4.0416492444641401 +cos0018 cos 1.1622206624927296 -0.50400115461197081 -> 0.44884072613370379 0.4823469915034318 +cos0019 cos 1.628772864620884e-08 0.58205705428979282 -> 1.1742319995791435 -1.0024839481956604e-08 +cos0020 cos 2.6385212606111241 2.9886107100937296 -> -8.7209475927161417 -4.7748352107199796 +cos0021 cos 4.8048375263775256 0.0062248852898515658 -> 0.092318702015846243 0.0061983430422306142 +cos0022 cos 7.9914515433858515 0.71659966615501436 -> -0.17375439906936566 -0.77217043527294582 +cos0023 cos 0.45124351152540226 1.6992693993812158 -> 2.543477948972237 -1.1528193694875477 + +-- special values +cos1000 cos -0.0 0.0 -> 1.0 0.0 +cos1001 cos -inf 0.0 -> nan 0.0 invalid ignore-imag-sign +cos1002 cos nan 0.0 -> nan 0.0 ignore-imag-sign +cos1003 cos -inf 2.2999999999999998 -> nan nan invalid +cos1004 cos nan 2.2999999999999998 -> nan nan +cos1005 cos -0.0 inf -> inf 0.0 +cos1006 cos -1.3999999999999999 inf -> inf inf +cos1007 cos -2.7999999999999998 inf -> -inf inf +cos1008 cos -4.2000000000000002 inf -> -inf -inf +cos1009 cos -5.5999999999999996 inf -> inf -inf +cos1010 cos -7.0 inf -> inf inf +cos1011 cos -inf inf -> inf nan invalid ignore-real-sign +cos1012 cos nan inf -> inf nan +cos1013 cos -0.0 nan -> nan 0.0 ignore-imag-sign +cos1014 cos -2.2999999999999998 nan -> nan nan +cos1015 cos -inf nan -> nan nan +cos1016 cos nan nan -> nan nan +cos1017 cos 0.0 0.0 -> 1.0 -0.0 +cos1018 cos inf 0.0 -> nan 0.0 invalid ignore-imag-sign +cos1019 cos inf 2.2999999999999998 -> nan nan invalid +cos1020 cos 0.0 inf -> inf -0.0 +cos1021 cos 1.3999999999999999 inf -> inf -inf +cos1022 cos 2.7999999999999998 inf -> -inf -inf +cos1023 cos 4.2000000000000002 inf -> -inf inf +cos1024 cos 5.5999999999999996 inf -> inf inf +cos1025 cos 7.0 inf -> inf -inf +cos1026 cos inf inf -> inf nan invalid ignore-real-sign +cos1027 cos 0.0 nan -> nan 0.0 ignore-imag-sign +cos1028 cos 2.2999999999999998 nan -> nan nan +cos1029 cos inf nan -> nan nan +cos1030 cos 0.0 -0.0 -> 1.0 0.0 +cos1031 cos inf -0.0 -> nan 0.0 invalid ignore-imag-sign +cos1032 cos nan -0.0 -> nan 0.0 ignore-imag-sign +cos1033 cos inf -2.2999999999999998 -> nan nan invalid +cos1034 cos nan -2.2999999999999998 -> nan nan +cos1035 cos 0.0 -inf -> inf 0.0 +cos1036 cos 1.3999999999999999 -inf -> inf inf +cos1037 cos 2.7999999999999998 -inf -> -inf inf +cos1038 cos 4.2000000000000002 -inf -> -inf -inf +cos1039 cos 5.5999999999999996 -inf -> inf -inf +cos1040 cos 7.0 -inf -> inf inf +cos1041 cos inf -inf -> inf nan invalid ignore-real-sign +cos1042 cos nan -inf -> inf nan +cos1043 cos -0.0 -0.0 -> 1.0 -0.0 +cos1044 cos -inf -0.0 -> nan 0.0 invalid ignore-imag-sign +cos1045 cos -inf -2.2999999999999998 -> nan nan invalid +cos1046 cos -0.0 -inf -> inf -0.0 +cos1047 cos -1.3999999999999999 -inf -> inf -inf +cos1048 cos -2.7999999999999998 -inf -> -inf -inf +cos1049 cos -4.2000000000000002 -inf -> -inf inf +cos1050 cos -5.5999999999999996 -inf -> inf inf +cos1051 cos -7.0 -inf -> inf -inf +cos1052 cos -inf -inf -> inf nan invalid ignore-real-sign + + +--------------- +-- sin: Sine -- +--------------- + +-- zeros +sin0000 sin 0.0 0.0 -> 0.0 0.0 +sin0001 sin 0.0 -0.0 -> 0.0 -0.0 +sin0002 sin -0.0 0.0 -> -0.0 0.0 +sin0003 sin -0.0 -0.0 -> -0.0 -0.0 + +-- random inputs +sin0004 sin -0.18691829163163759 -0.74388741985507034 -> -0.2396636733773444 -0.80023231101856751 +sin0005 sin -0.45127453702459158 -461.81339920716164 -> -7.9722299331077877e+199 -1.6450205811004628e+200 +sin0006 sin -0.47669228345768921 -2.7369936564987514 -> -3.557238022267124 -6.8308030771226615 +sin0007 sin -0.31024285525950857 -1.4869219939188296 -> -0.70972676047175209 -1.9985029635426839 +sin0008 sin -4.4194573407025608 -1.405999210989288 -> 2.0702480800802685 0.55362250792180601 +sin0009 sin -1.7810832046434898e-05 0.0016439555384379083 -> -1.7810856113185261e-05 0.0016439562786668375 +sin0010 sin -0.8200017874897666 0.61724876887771929 -> -0.8749078195948865 0.44835295550987758 +sin0011 sin -1.4536502806107114 0.63998575534150415 -> -1.2035709929437679 0.080012187489163708 +sin0012 sin -2.2653412155506079 0.13172760685583729 -> -0.77502093809190431 -0.084554426868229532 +sin0013 sin -0.02613983069491858 0.18404766597776073 -> -0.026580778863127943 0.18502525396735642 +sin0014 sin 1.5743065001054617 -0.53125574272642029 -> 1.1444596332092725 0.0019537598099352077 +sin0015 sin 7.3833101791283289e-20 -0.16453221324236217 -> 7.4834720674379429e-20 -0.16527555646466915 +sin0016 sin 0.34763834641254038 -2.8377416421089565 -> 2.918883541504663 -8.0002718053250224 +sin0017 sin 0.077105785180421563 -0.090056027316200674 -> 0.077341973814471304 -0.089909869380524587 +sin0018 sin 3.9063227798142329e-17 -0.05954098654295524 -> 3.9132490348956512e-17 -0.059576172859837351 +sin0019 sin 0.57333917932544598 8.7785221430594696e-06 -> 0.54244029338302935 7.3747869125301368e-06 +sin0020 sin 0.024861722816513169 0.33044620756118515 -> 0.026228801369651 0.3363889671570689 +sin0021 sin 1.4342727387492671 0.81361889790284347 -> 1.3370960060947923 0.12336137961387163 +sin0022 sin 1.1518087354403725 4.8597235966150558 -> 58.919141989603041 26.237003403758852 +sin0023 sin 0.00087773078406649192 34.792379211312095 -> 565548145569.38245 644329685822700.62 + +-- special values +sin1000 sin -0.0 0.0 -> -0.0 0.0 +sin1001 sin -inf 0.0 -> nan 0.0 invalid ignore-imag-sign +sin1002 sin nan 0.0 -> nan 0.0 ignore-imag-sign +sin1003 sin -inf 2.2999999999999998 -> nan nan invalid +sin1004 sin nan 2.2999999999999998 -> nan nan +sin1005 sin -0.0 inf -> -0.0 inf +sin1006 sin -1.3999999999999999 inf -> -inf inf +sin1007 sin -2.7999999999999998 inf -> -inf -inf +sin1008 sin -4.2000000000000002 inf -> inf -inf +sin1009 sin -5.5999999999999996 inf -> inf inf +sin1010 sin -7.0 inf -> -inf inf +sin1011 sin -inf inf -> nan inf invalid ignore-imag-sign +sin1012 sin nan inf -> nan inf ignore-imag-sign +sin1013 sin -0.0 nan -> -0.0 nan +sin1014 sin -2.2999999999999998 nan -> nan nan +sin1015 sin -inf nan -> nan nan +sin1016 sin nan nan -> nan nan +sin1017 sin 0.0 0.0 -> 0.0 0.0 +sin1018 sin inf 0.0 -> nan 0.0 invalid ignore-imag-sign +sin1019 sin inf 2.2999999999999998 -> nan nan invalid +sin1020 sin 0.0 inf -> 0.0 inf +sin1021 sin 1.3999999999999999 inf -> inf inf +sin1022 sin 2.7999999999999998 inf -> inf -inf +sin1023 sin 4.2000000000000002 inf -> -inf -inf +sin1024 sin 5.5999999999999996 inf -> -inf inf +sin1025 sin 7.0 inf -> inf inf +sin1026 sin inf inf -> nan inf invalid ignore-imag-sign +sin1027 sin 0.0 nan -> 0.0 nan +sin1028 sin 2.2999999999999998 nan -> nan nan +sin1029 sin inf nan -> nan nan +sin1030 sin 0.0 -0.0 -> 0.0 -0.0 +sin1031 sin inf -0.0 -> nan 0.0 invalid ignore-imag-sign +sin1032 sin nan -0.0 -> nan 0.0 ignore-imag-sign +sin1033 sin inf -2.2999999999999998 -> nan nan invalid +sin1034 sin nan -2.2999999999999998 -> nan nan +sin1035 sin 0.0 -inf -> 0.0 -inf +sin1036 sin 1.3999999999999999 -inf -> inf -inf +sin1037 sin 2.7999999999999998 -inf -> inf inf +sin1038 sin 4.2000000000000002 -inf -> -inf inf +sin1039 sin 5.5999999999999996 -inf -> -inf -inf +sin1040 sin 7.0 -inf -> inf -inf +sin1041 sin inf -inf -> nan inf invalid ignore-imag-sign +sin1042 sin nan -inf -> nan inf ignore-imag-sign +sin1043 sin -0.0 -0.0 -> -0.0 -0.0 +sin1044 sin -inf -0.0 -> nan 0.0 invalid ignore-imag-sign +sin1045 sin -inf -2.2999999999999998 -> nan nan invalid +sin1046 sin -0.0 -inf -> -0.0 -inf +sin1047 sin -1.3999999999999999 -inf -> -inf -inf +sin1048 sin -2.7999999999999998 -inf -> -inf inf +sin1049 sin -4.2000000000000002 -inf -> inf inf +sin1050 sin -5.5999999999999996 -inf -> inf -inf +sin1051 sin -7.0 -inf -> -inf -inf +sin1052 sin -inf -inf -> nan inf invalid ignore-imag-sign + + +------------------ +-- tan: Tangent -- +------------------ + +-- zeros +tan0000 tan 0.0 0.0 -> 0.0 0.0 +tan0001 tan 0.0 -0.0 -> 0.0 -0.0 +tan0002 tan -0.0 0.0 -> -0.0 0.0 +tan0003 tan -0.0 -0.0 -> -0.0 -0.0 + +-- random inputs +tan0004 tan -0.56378561833861074 -1.7110276237187664e+73 -> -0.0 -1.0 +tan0005 tan -3.5451633993471915e-12 -2.855471863564059 -> -4.6622441304889575e-14 -0.99340273843093951 +tan0006 tan -2.502442719638696 -0.26742234390504221 -> 0.66735215252994995 -0.39078997935420956 +tan0007 tan -0.87639597720371365 -55.586225523280206 -> -1.0285264565948176e-48 -1.0 +tan0008 tan -0.015783869596427243 -520.05944436039272 -> -0.0 -1.0 +tan0009 tan -0.84643549990725164 2.0749097935396343 -> -0.031412661676959573 1.0033548479526764 +tan0010 tan -0.43613792248559646 8.1082741629458059 -> -1.3879848444644593e-07 0.99999988344224011 +tan0011 tan -1.0820906367833114 0.28571868992480248 -> -1.3622485737936536 0.99089269377971245 +tan0012 tan -1.1477859580220084 1.9021637002708041 -> -0.034348450042071196 1.0293954097901687 +tan0013 tan -0.12465543176953409 3.0606851016344815e-05 -> -0.12530514290387343 3.1087420769945479e-05 +tan0014 tan 3.7582848717525343 -692787020.44038939 -> 0.0 -1.0 +tan0015 tan 2.2321967655142176e-06 -10.090069423008169 -> 1.5369846120622643e-14 -0.99999999655723759 +tan0016 tan 0.88371172390245012 -1.1635053630132823 -> 0.19705017118625889 -1.0196452280843129 +tan0017 tan 2.1347414231849267 -1.9311339960416831 -> -0.038663576915982524 -1.0174399993980778 +tan0018 tan 5.9027945255899974 -2.1574195684607135e-183 -> -0.39986591539281496 -2.5023753167976915e-183 +tan0019 tan 0.44811489490805362 683216075670.07556 -> 0.0 1.0 +tan0020 tan 4.1459766396068325 12.523017205605756 -> 2.4022514758988068e-11 1.0000000000112499 +tan0021 tan 1.7809617968443272 1.5052381702853379 -> -0.044066222118946903 1.0932684517702778 +tan0022 tan 1.1615313900880577 1.7956298728647107 -> 0.041793186826390362 1.0375339546034792 +tan0023 tan 0.067014779477908945 5.8517361577457097 -> 2.2088639754800034e-06 0.9999836182420061 + +-- special values +tan1000 tan -0.0 0.0 -> -0.0 0.0 +tan1001 tan -inf 0.0 -> nan nan invalid +tan1002 tan -inf 2.2999999999999998 -> nan nan invalid +tan1003 tan nan 0.0 -> nan nan +tan1004 tan nan 2.2999999999999998 -> nan nan +tan1005 tan -0.0 inf -> -0.0 1.0 +tan1006 tan -0.69999999999999996 inf -> -0.0 1.0 +tan1007 tan -1.3999999999999999 inf -> -0.0 1.0 +tan1008 tan -2.1000000000000001 inf -> 0.0 1.0 +tan1009 tan -2.7999999999999998 inf -> 0.0 1.0 +tan1010 tan -3.5 inf -> -0.0 1.0 +tan1011 tan -inf inf -> -0.0 1.0 ignore-real-sign +tan1012 tan nan inf -> -0.0 1.0 ignore-real-sign +tan1013 tan -0.0 nan -> -0.0 nan +tan1014 tan -2.2999999999999998 nan -> nan nan +tan1015 tan -inf nan -> nan nan +tan1016 tan nan nan -> nan nan +tan1017 tan 0.0 0.0 -> 0.0 0.0 +tan1018 tan inf 0.0 -> nan nan invalid +tan1019 tan inf 2.2999999999999998 -> nan nan invalid +tan1020 tan 0.0 inf -> 0.0 1.0 +tan1021 tan 0.69999999999999996 inf -> 0.0 1.0 +tan1022 tan 1.3999999999999999 inf -> 0.0 1.0 +tan1023 tan 2.1000000000000001 inf -> -0.0 1.0 +tan1024 tan 2.7999999999999998 inf -> -0.0 1.0 +tan1025 tan 3.5 inf -> 0.0 1.0 +tan1026 tan inf inf -> -0.0 1.0 ignore-real-sign +tan1027 tan 0.0 nan -> 0.0 nan +tan1028 tan 2.2999999999999998 nan -> nan nan +tan1029 tan inf nan -> nan nan +tan1030 tan 0.0 -0.0 -> 0.0 -0.0 +tan1031 tan inf -0.0 -> nan nan invalid +tan1032 tan inf -2.2999999999999998 -> nan nan invalid +tan1033 tan nan -0.0 -> nan nan +tan1034 tan nan -2.2999999999999998 -> nan nan +tan1035 tan 0.0 -inf -> 0.0 -1.0 +tan1036 tan 0.69999999999999996 -inf -> 0.0 -1.0 +tan1037 tan 1.3999999999999999 -inf -> 0.0 -1.0 +tan1038 tan 2.1000000000000001 -inf -> -0.0 -1.0 +tan1039 tan 2.7999999999999998 -inf -> -0.0 -1.0 +tan1040 tan 3.5 -inf -> 0.0 -1.0 +tan1041 tan inf -inf -> -0.0 -1.0 ignore-real-sign +tan1042 tan nan -inf -> -0.0 -1.0 ignore-real-sign +tan1043 tan -0.0 -0.0 -> -0.0 -0.0 +tan1044 tan -inf -0.0 -> nan nan invalid +tan1045 tan -inf -2.2999999999999998 -> nan nan invalid +tan1046 tan -0.0 -inf -> -0.0 -1.0 +tan1047 tan -0.69999999999999996 -inf -> -0.0 -1.0 +tan1048 tan -1.3999999999999999 -inf -> -0.0 -1.0 +tan1049 tan -2.1000000000000001 -inf -> 0.0 -1.0 +tan1050 tan -2.7999999999999998 -inf -> 0.0 -1.0 +tan1051 tan -3.5 -inf -> -0.0 -1.0 +tan1052 tan -inf -inf -> -0.0 -1.0 ignore-real-sign + + +------------------------------------------------------------------------ +-- rect: Conversion from polar coordinates to rectangular coordinates -- +------------------------------------------------------------------------ +-- +-- For cmath.rect, we can use the same testcase syntax as for the +-- complex -> complex functions above, but here the input arguments +-- should be interpreted as a pair of floating-point numbers rather +-- than the real and imaginary parts of a complex number. +-- +-- Here are the 'spirit of C99' rules for rect. First, the short +-- version: +-- +-- rect(x, t) = exp(log(x)+it) for positive-signed x +-- rect(x, t) = -exp(log(-x)+it) for negative-signed x +-- rect(nan, t) = exp(nan + it), except that in rect(nan, +-0) the +-- sign of the imaginary part is unspecified. +-- +-- and now the long version: +-- +-- rect(x, -t) = conj(rect(x, t)) for all x and t +-- rect(-x, t) = -rect(x, t) for all x and t +-- rect(+0, +0) returns +0 + i0 +-- rect(+0, inf) returns +- 0 +- i0, where the signs of the real and +-- imaginary parts are unspecified. +-- rect(x, inf) returns NaN + i NaN and raises the "invalid" +-- floating-point exception, for finite nonzero x. +-- rect(inf, inf) returns +-inf + i NaN and raises the "invalid" +-- floating-point exception (where the sign of the real part of the +-- result is unspecified). +-- rect(inf, +0) returns inf+i0 +-- rect(inf, x) returns inf*cis(x), for finite nonzero x +-- rect(inf, NaN) returns +-inf+i NaN, where the sign of the real part +-- of the result is unspecified. +-- rect(NaN, x) returns NaN + i NaN for all nonzero numbers (including +-- infinities) x +-- rect(NaN, 0) returns NaN +- i0, where the sign of the imaginary +-- part is unspecified +-- rect(NaN, NaN) returns NaN + i NaN +-- rect(x, NaN) returns NaN + i NaN for finite nonzero x +-- rect(+0, NaN) return +-0 +- i0, where the signs of the real and +-- imaginary parts are unspecified. + +-- special values +rect1000 rect 0.0 0.0 -> 0.0 0.0 +rect1001 rect 0.0 inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1002 rect 2.3 inf -> nan nan invalid +rect1003 rect inf inf -> inf nan invalid ignore-real-sign +rect1004 rect inf 0.0 -> inf 0.0 +rect1005 rect inf 1.4 -> inf inf +rect1006 rect inf 2.8 -> -inf inf +rect1007 rect inf 4.2 -> -inf -inf +rect1008 rect inf 5.6 -> inf -inf +rect1009 rect inf 7.0 -> inf inf +rect1010 rect nan 0.0 -> nan 0.0 ignore-imag-sign +rect1011 rect nan 2.3 -> nan nan +rect1012 rect nan inf -> nan nan +rect1013 rect nan nan -> nan nan +rect1014 rect inf nan -> inf nan ignore-real-sign +rect1015 rect 2.3 nan -> nan nan +rect1016 rect 0.0 nan -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1017 rect 0.0 -0.0 -> 0.0 -0.0 +rect1018 rect 0.0 -inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1019 rect 2.3 -inf -> nan nan invalid +rect1020 rect inf -inf -> inf nan invalid ignore-real-sign +rect1021 rect inf -0.0 -> inf -0.0 +rect1022 rect inf -1.4 -> inf -inf +rect1023 rect inf -2.8 -> -inf -inf +rect1024 rect inf -4.2 -> -inf inf +rect1025 rect inf -5.6 -> inf inf +rect1026 rect inf -7.0 -> inf -inf +rect1027 rect nan -0.0 -> nan 0.0 ignore-imag-sign +rect1028 rect nan -2.3 -> nan nan +rect1029 rect nan -inf -> nan nan +rect1030 rect -0.0 0.0 -> -0.0 -0.0 +rect1031 rect -0.0 inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1032 rect -2.3 inf -> nan nan invalid +rect1033 rect -inf inf -> -inf nan invalid ignore-real-sign +rect1034 rect -inf 0.0 -> -inf -0.0 +rect1035 rect -inf 1.4 -> -inf -inf +rect1036 rect -inf 2.8 -> inf -inf +rect1037 rect -inf 4.2 -> inf inf +rect1038 rect -inf 5.6 -> -inf inf +rect1039 rect -inf 7.0 -> -inf -inf +rect1040 rect -inf nan -> inf nan ignore-real-sign +rect1041 rect -2.3 nan -> nan nan +rect1042 rect -0.0 nan -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1043 rect -0.0 -0.0 -> -0.0 0.0 +rect1044 rect -0.0 -inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1045 rect -2.3 -inf -> nan nan invalid +rect1046 rect -inf -inf -> -inf nan invalid ignore-real-sign +rect1047 rect -inf -0.0 -> -inf 0.0 +rect1048 rect -inf -1.4 -> -inf inf +rect1049 rect -inf -2.8 -> inf inf +rect1050 rect -inf -4.2 -> inf -inf +rect1051 rect -inf -5.6 -> -inf -inf +rect1052 rect -inf -7.0 -> -inf inf + +------------------------------------------------------------------------- +-- polar: Conversion from rectangular coordinates to polar coordinates -- +------------------------------------------------------------------------- +-- +-- For cmath.polar, we can use the same testcase syntax as for the +-- complex -> complex functions above, but here the output arguments +-- should be interpreted as a pair of floating-point numbers rather +-- than the real and imaginary parts of a complex number. +-- +-- Annex G of the C99 standard describes fully both the real and +-- imaginary parts of polar (as cabs and carg, respectively, which in turn +-- are defined in terms of the functions hypot and atan2). + +-- overflow +polar0100 polar 1.4e308 1.4e308 -> inf 0.78539816339744828 overflow + +-- special values +polar1000 polar 0.0 0.0 -> 0.0 0.0 +polar1001 polar 0.0 -0.0 -> 0.0 -0.0 +polar1002 polar -0.0 0.0 -> 0.0 3.1415926535897931 +polar1003 polar -0.0 -0.0 -> 0.0 -3.1415926535897931 +polar1004 polar inf 0.0 -> inf 0.0 +polar1005 polar inf 2.3 -> inf 0.0 +polar1006 polar inf inf -> inf 0.78539816339744828 +polar1007 polar 2.3 inf -> inf 1.5707963267948966 +polar1008 polar 0.0 inf -> inf 1.5707963267948966 +polar1009 polar -0.0 inf -> inf 1.5707963267948966 +polar1010 polar -2.3 inf -> inf 1.5707963267948966 +polar1011 polar -inf inf -> inf 2.3561944901923448 +polar1012 polar -inf 2.3 -> inf 3.1415926535897931 +polar1013 polar -inf 0.0 -> inf 3.1415926535897931 +polar1014 polar -inf -0.0 -> inf -3.1415926535897931 +polar1015 polar -inf -2.3 -> inf -3.1415926535897931 +polar1016 polar -inf -inf -> inf -2.3561944901923448 +polar1017 polar -2.3 -inf -> inf -1.5707963267948966 +polar1018 polar -0.0 -inf -> inf -1.5707963267948966 +polar1019 polar 0.0 -inf -> inf -1.5707963267948966 +polar1020 polar 2.3 -inf -> inf -1.5707963267948966 +polar1021 polar inf -inf -> inf -0.78539816339744828 +polar1022 polar inf -2.3 -> inf -0.0 +polar1023 polar inf -0.0 -> inf -0.0 +polar1024 polar nan -inf -> inf nan +polar1025 polar nan -2.3 -> nan nan +polar1026 polar nan -0.0 -> nan nan +polar1027 polar nan 0.0 -> nan nan +polar1028 polar nan 2.3 -> nan nan +polar1029 polar nan inf -> inf nan +polar1030 polar nan nan -> nan nan +polar1031 polar inf nan -> inf nan +polar1032 polar 2.3 nan -> nan nan +polar1033 polar 0.0 nan -> nan nan +polar1034 polar -0.0 nan -> nan nan +polar1035 polar -2.3 nan -> nan nan +polar1036 polar -inf nan -> inf nan -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 20:23:01 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 06 Jan 2015 19:23:01 +0000 Subject: [Jython-checkins] =?utf-8?q?jython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_recent_work_on_math_module?= Message-ID: <20150106192300.22403.38689@psf.io> https://hg.python.org/jython/rev/82dbfa5df494 changeset: 7511:82dbfa5df494 parent: 7503:e12953dc5e40 parent: 7510:44cfecd93257 user: Jeff Allen date: Tue Jan 06 19:22:29 2015 +0000 summary: Merge recent work on math module files: Lib/test/cmath_testcases.txt | 2502 ++++++++++++++++++ Lib/test/test_cmath.py | 7 +- Lib/test/test_math.py | 3 +- Lib/test/test_math_jy.py | 103 +- Misc/make_cmath_testcases.py | 124 + src/org/python/modules/math.java | 326 +- 6 files changed, 2853 insertions(+), 212 deletions(-) diff --git a/Lib/test/cmath_testcases.txt b/Lib/test/cmath_testcases.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cmath_testcases.txt @@ -0,0 +1,2502 @@ +-- Testcases for functions in cmath. +-- +-- Each line takes the form: +-- +-- -> +-- +-- where: +-- +-- is a short name identifying the test, +-- +-- is the function to be tested (exp, cos, asinh, ...), +-- +-- is a pair of floats separated by whitespace +-- representing real and imaginary parts of a complex number, and +-- +-- is the expected (ideal) output value, again +-- represented as a pair of floats. +-- +-- is a list of the floating-point flags required by C99 +-- +-- The possible flags are: +-- +-- divide-by-zero : raised when a finite input gives a +-- mathematically infinite result. +-- +-- overflow : raised when a finite input gives a finite result whose +-- real or imaginary part is too large to fit in the usual range +-- of an IEEE 754 double. +-- +-- invalid : raised for invalid inputs. +-- +-- ignore-real-sign : indicates that the sign of the real part of +-- the result is unspecified; if the real part of the result is +-- given as inf, then both -inf and inf should be accepted as +-- correct. +-- +-- ignore-imag-sign : indicates that the sign of the imaginary part +-- of the result is unspecified. +-- +-- Flags may appear in any order. +-- +-- Lines beginning with '--' (like this one) start a comment, and are +-- ignored. Blank lines, or lines containing only whitespace, are also +-- ignored. + +-- The majority of the values below were computed with the help of +-- version 2.3 of the MPFR library for multiple-precision +-- floating-point computations with correct rounding. All output +-- values in this file are (modulo yet-to-be-discovered bugs) +-- correctly rounded, provided that each input and output decimal +-- floating-point value below is interpreted as a representation of +-- the corresponding nearest IEEE 754 double-precision value. See the +-- MPFR homepage at http://www.mpfr.org for more information about the +-- MPFR project. + +-- A minority of the test cases were generated with the help of +-- mpmath 0.19 at 100 bit accuracy (http://mpmath.org) to provide +-- coverage of real functions with real-valued arguments. These are +-- used particularly in test.test_math.MathTests.test_testfile. +-- These additions were made originally for the Jython project. + + +-------------------------- +-- acos: Inverse cosine -- +-------------------------- + +-- zeros +acos0000 acos 0.0 0.0 -> 1.5707963267948966 -0.0 +acos0001 acos 0.0 -0.0 -> 1.5707963267948966 0.0 +acos0002 acos -0.0 0.0 -> 1.5707963267948966 -0.0 +acos0003 acos -0.0 -0.0 -> 1.5707963267948966 0.0 + +-- branch points: +/-1 +acos0010 acos 1.0 0.0 -> 0.0 -0.0 +acos0011 acos 1.0 -0.0 -> 0.0 0.0 +acos0012 acos -1.0 0.0 -> 3.1415926535897931 -0.0 +acos0013 acos -1.0 -0.0 -> 3.1415926535897931 0.0 + +-- values along both sides of real axis +acos0020 acos -9.8813129168249309e-324 0.0 -> 1.5707963267948966 -0.0 +acos0021 acos -9.8813129168249309e-324 -0.0 -> 1.5707963267948966 0.0 +acos0022 acos -1e-305 0.0 -> 1.5707963267948966 -0.0 +acos0023 acos -1e-305 -0.0 -> 1.5707963267948966 0.0 +acos0024 acos -1e-150 0.0 -> 1.5707963267948966 -0.0 +acos0025 acos -1e-150 -0.0 -> 1.5707963267948966 0.0 +acos0026 acos -9.9999999999999998e-17 0.0 -> 1.5707963267948968 -0.0 +acos0027 acos -9.9999999999999998e-17 -0.0 -> 1.5707963267948968 0.0 +acos0028 acos -0.001 0.0 -> 1.5717963269615634 -0.0 +acos0029 acos -0.001 -0.0 -> 1.5717963269615634 0.0 +acos0030 acos -0.57899999999999996 0.0 -> 2.1882979816120667 -0.0 +acos0031 acos -0.57899999999999996 -0.0 -> 2.1882979816120667 0.0 +acos0032 acos -0.99999999999999989 0.0 -> 3.1415926386886319 -0.0 +acos0033 acos -0.99999999999999989 -0.0 -> 3.1415926386886319 0.0 +acos0034 acos -1.0000000000000002 0.0 -> 3.1415926535897931 -2.1073424255447014e-08 +acos0035 acos -1.0000000000000002 -0.0 -> 3.1415926535897931 2.1073424255447014e-08 +acos0036 acos -1.0009999999999999 0.0 -> 3.1415926535897931 -0.044717633608306849 +acos0037 acos -1.0009999999999999 -0.0 -> 3.1415926535897931 0.044717633608306849 +acos0038 acos -2.0 0.0 -> 3.1415926535897931 -1.3169578969248168 +acos0039 acos -2.0 -0.0 -> 3.1415926535897931 1.3169578969248168 +acos0040 acos -23.0 0.0 -> 3.1415926535897931 -3.8281684713331012 +acos0041 acos -23.0 -0.0 -> 3.1415926535897931 3.8281684713331012 +acos0042 acos -10000000000000000.0 0.0 -> 3.1415926535897931 -37.534508668464674 +acos0043 acos -10000000000000000.0 -0.0 -> 3.1415926535897931 37.534508668464674 +acos0044 acos -9.9999999999999998e+149 0.0 -> 3.1415926535897931 -346.08091112966679 +acos0045 acos -9.9999999999999998e+149 -0.0 -> 3.1415926535897931 346.08091112966679 +acos0046 acos -1.0000000000000001e+299 0.0 -> 3.1415926535897931 -689.16608998577965 +acos0047 acos -1.0000000000000001e+299 -0.0 -> 3.1415926535897931 689.16608998577965 +acos0048 acos 9.8813129168249309e-324 0.0 -> 1.5707963267948966 -0.0 +acos0049 acos 9.8813129168249309e-324 -0.0 -> 1.5707963267948966 0.0 +acos0050 acos 1e-305 0.0 -> 1.5707963267948966 -0.0 +acos0051 acos 1e-305 -0.0 -> 1.5707963267948966 0.0 +acos0052 acos 1e-150 0.0 -> 1.5707963267948966 -0.0 +acos0053 acos 1e-150 -0.0 -> 1.5707963267948966 0.0 +acos0054 acos 9.9999999999999998e-17 0.0 -> 1.5707963267948966 -0.0 +acos0055 acos 9.9999999999999998e-17 -0.0 -> 1.5707963267948966 0.0 +acos0056 acos 0.001 0.0 -> 1.56979632662823 -0.0 +acos0057 acos 0.001 -0.0 -> 1.56979632662823 0.0 +acos0058 acos 0.57899999999999996 0.0 -> 0.95329467197772655 -0.0 +acos0059 acos 0.57899999999999996 -0.0 -> 0.95329467197772655 0.0 +acos0060 acos 0.99999999999999989 0.0 -> 1.4901161193847656e-08 -0.0 +acos0061 acos 0.99999999999999989 -0.0 -> 1.4901161193847656e-08 0.0 +acos0062 acos 1.0000000000000002 0.0 -> 0.0 -2.1073424255447014e-08 +acos0063 acos 1.0000000000000002 -0.0 -> 0.0 2.1073424255447014e-08 +acos0064 acos 1.0009999999999999 0.0 -> 0.0 -0.044717633608306849 +acos0065 acos 1.0009999999999999 -0.0 -> 0.0 0.044717633608306849 +acos0066 acos 2.0 0.0 -> 0.0 -1.3169578969248168 +acos0067 acos 2.0 -0.0 -> 0.0 1.3169578969248168 +acos0068 acos 23.0 0.0 -> 0.0 -3.8281684713331012 +acos0069 acos 23.0 -0.0 -> 0.0 3.8281684713331012 +acos0070 acos 10000000000000000.0 0.0 -> 0.0 -37.534508668464674 +acos0071 acos 10000000000000000.0 -0.0 -> 0.0 37.534508668464674 +acos0072 acos 9.9999999999999998e+149 0.0 -> 0.0 -346.08091112966679 +acos0073 acos 9.9999999999999998e+149 -0.0 -> 0.0 346.08091112966679 +acos0074 acos 1.0000000000000001e+299 0.0 -> 0.0 -689.16608998577965 +acos0075 acos 1.0000000000000001e+299 -0.0 -> 0.0 689.16608998577965 + +-- random inputs +acos0100 acos -3.3307113324596682 -10.732007530863266 -> 1.8706085694482339 3.113986806554613 +acos0101 acos -2863.952991743291 -2681013315.2571239 -> 1.5707973950301699 22.402607843274758 +acos0102 acos -0.33072639793220088 -0.85055464658253055 -> 1.8219426895922601 0.79250166729311966 +acos0103 acos -2.5722325842097802 -12.703940809821574 -> 1.7699942413107408 3.2565170156527325 +acos0104 acos -42.495233785459583 -0.54039320751337161 -> 3.1288732573153304 4.4424815519735601 +acos0105 acos -1.1363818625856401 9641.1325498630376 -> 1.5709141948820049 -9.8669410553254284 +acos0106 acos -2.4398426824157866e-11 0.33002051890266165 -> 1.570796326818066 -0.32430578041578667 +acos0107 acos -1.3521340428186552 2.9369737912076772 -> 1.9849059192339338 -1.8822893674117942 +acos0108 acos -1.827364706477915 1.0355459232147557 -> 2.5732246307960032 -1.4090688267854969 +acos0109 acos -0.25978373706403546 10.09712669185833 -> 1.5963940386378306 -3.0081673050196063 +acos0110 acos 0.33561778471072551 -4587350.6823999118 -> 1.5707962536333251 16.031960402579539 +acos0111 acos 0.49133444610998445 -0.8071422362990015 -> 1.1908761712801788 0.78573345813187867 +acos0112 acos 0.42196734507823974 -2.4812965431745115 -> 1.414091186100692 1.651707260988172 +acos0113 acos 2.961426210100655 -219.03295695248664 -> 1.5572768319822778 6.0824659885827304 +acos0114 acos 2.886209063652641 -20.38011207220606 -> 1.4302765252297889 3.718201853147642 +acos0115 acos 0.4180568075276509 1.4833433990823484 -> 1.3393834558303042 -1.2079847758301576 +acos0116 acos 52.376111405924718 0.013930429001941001 -> 0.00026601761804024188 -4.6515066691204714 +acos0117 acos 41637948387.625969 1.563418292894041 -> 3.7547918507883548e-11 -25.145424989809381 +acos0118 acos 0.061226659122249526 0.8447234394615154 -> 1.5240280306367315 -0.76791798971140812 +acos0119 acos 2.4480466420442959e+26 0.18002339201384662 -> 7.353756620564798e-28 -61.455650015996376 + +-- values near infinity +acos0200 acos 1.6206860518683021e+308 1.0308426226285283e+308 -> 0.56650826093826223 -710.54206874241561 +acos0201 acos 1.2067735875070062e+308 -1.3429173724390276e+308 -> 0.83874369390864889 710.48017794027498 +acos0202 acos -7.4130145132549047e+307 1.1759130543927645e+308 -> 2.1332729346478536 -710.21871115698752 +acos0203 acos -8.6329426442257249e+307 -1.2316282952184133e+308 -> 2.1821511032444838 710.29752145697148 +acos0204 acos 0.0 1.4289713855849746e+308 -> 1.5707963267948966 -710.24631069738996 +acos0205 acos -0.0 1.3153524545987432e+308 -> 1.5707963267948966 -710.1634604787539 +acos0206 acos 0.0 -9.6229037669269321e+307 -> 1.5707963267948966 709.85091679573691 +acos0207 acos -0.0 -4.9783616421107088e+307 -> 1.5707963267948966 709.19187157911233 +acos0208 acos 1.3937541925739389e+308 0.0 -> 0.0 -710.22135678707264 +acos0209 acos 9.1362388967371536e+307 -0.0 -> 0.0 709.79901953124613 +acos0210 acos -1.3457361220697436e+308 0.0 -> 3.1415926535897931 -710.18629698871848 +acos0211 acos -5.4699090056144284e+307 -0.0 -> 3.1415926535897931 709.28603271085649 +acos0212 acos 1.5880716932358901e+308 5.5638401252339929 -> 3.503519487773873e-308 -710.35187633140583 +acos0213 acos 1.2497211663463164e+308 -3.0456477717911024 -> 2.4370618453197486e-308 710.11227628223412 +acos0214 acos -9.9016224006029528e+307 4.9570427340789056 -> 3.1415926535897931 -709.87946935229468 +acos0215 acos -1.5854071066874139e+308 -4.4233577741497783 -> 3.1415926535897931 710.35019704672004 +acos0216 acos 9.3674623083647628 1.5209559051877979e+308 -> 1.5707963267948966 -710.30869484491086 +acos0217 acos 8.1773832021784383 -6.6093445795000056e+307 -> 1.5707963267948966 709.4752552227792 +acos0218 acos -3.1845935000665104 1.5768856396650893e+308 -> 1.5707963267948966 -710.34480761042687 +acos0219 acos -1.0577303880953903 -6.4574626815735613e+307 -> 1.5707963267948966 709.45200719662046 + +-- values near 0 +acos0220 acos 1.8566986970714045e-320 3.1867234156760402e-321 -> 1.5707963267948966 -3.1867234156760402e-321 +acos0221 acos 7.9050503334599447e-323 -8.8931816251424378e-323 -> 1.5707963267948966 8.8931816251424378e-323 +acos0222 acos -4.4465908125712189e-323 2.4654065097222727e-311 -> 1.5707963267948966 -2.4654065097222727e-311 +acos0223 acos -6.1016916408192619e-311 -2.4703282292062327e-323 -> 1.5707963267948966 2.4703282292062327e-323 +acos0224 acos 0.0 3.4305783621842729e-311 -> 1.5707963267948966 -3.4305783621842729e-311 +acos0225 acos -0.0 1.6117409498633145e-319 -> 1.5707963267948966 -1.6117409498633145e-319 +acos0226 acos 0.0 -4.9900630229965901e-322 -> 1.5707963267948966 4.9900630229965901e-322 +acos0227 acos -0.0 -4.4889279210592818e-311 -> 1.5707963267948966 4.4889279210592818e-311 +acos0228 acos 5.3297678681477214e-312 0.0 -> 1.5707963267948966 -0.0 +acos0229 acos 6.2073425897211614e-313 -0.0 -> 1.5707963267948966 0.0 +acos0230 acos -4.9406564584124654e-324 0.0 -> 1.5707963267948966 -0.0 +acos0231 acos -1.7107517052899003e-318 -0.0 -> 1.5707963267948966 0.0 + +-- special values +acos1000 acos 0.0 0.0 -> 1.5707963267948966 -0.0 +acos1001 acos 0.0 -0.0 -> 1.5707963267948966 0.0 +acos1002 acos -0.0 0.0 -> 1.5707963267948966 -0.0 +acos1003 acos -0.0 -0.0 -> 1.5707963267948966 0.0 +acos1004 acos 0.0 nan -> 1.5707963267948966 nan +acos1005 acos -0.0 nan -> 1.5707963267948966 nan +acos1006 acos -2.3 inf -> 1.5707963267948966 -inf +acos1007 acos -0.0 inf -> 1.5707963267948966 -inf +acos1008 acos 0.0 inf -> 1.5707963267948966 -inf +acos1009 acos 2.3 inf -> 1.5707963267948966 -inf +acos1010 acos -2.3 nan -> nan nan +acos1011 acos 2.3 nan -> nan nan +acos1012 acos -inf 2.3 -> 3.1415926535897931 -inf +acos1013 acos -inf 0.0 -> 3.1415926535897931 -inf +acos1014 acos inf 2.3 -> 0.0 -inf +acos1015 acos inf 0.0 -> 0.0 -inf +acos1016 acos -inf inf -> 2.3561944901923448 -inf +acos1017 acos inf inf -> 0.78539816339744828 -inf +acos1018 acos inf nan -> nan inf ignore-imag-sign +acos1019 acos -inf nan -> nan inf ignore-imag-sign +acos1020 acos nan 0.0 -> nan nan +acos1021 acos nan 2.3 -> nan nan +acos1022 acos nan inf -> nan -inf +acos1023 acos nan nan -> nan nan +acos1024 acos -2.3 -inf -> 1.5707963267948966 inf +acos1025 acos -0.0 -inf -> 1.5707963267948966 inf +acos1026 acos 0.0 -inf -> 1.5707963267948966 inf +acos1027 acos 2.3 -inf -> 1.5707963267948966 inf +acos1028 acos -inf -2.3 -> 3.1415926535897931 inf +acos1029 acos -inf -0.0 -> 3.1415926535897931 inf +acos1030 acos inf -2.3 -> 0.0 inf +acos1031 acos inf -0.0 -> 0.0 inf +acos1032 acos -inf -inf -> 2.3561944901923448 inf +acos1033 acos inf -inf -> 0.78539816339744828 inf +acos1034 acos nan -0.0 -> nan nan +acos1035 acos nan -2.3 -> nan nan +acos1036 acos nan -inf -> nan inf + + +-------------------------------------- +-- acosh: Inverse hyperbolic cosine -- +-------------------------------------- + +-- zeros +acosh0000 acosh 0.0 0.0 -> 0.0 1.5707963267948966 +acosh0001 acosh 0.0 -0.0 -> 0.0 -1.5707963267948966 +acosh0002 acosh -0.0 0.0 -> 0.0 1.5707963267948966 +acosh0003 acosh -0.0 -0.0 -> 0.0 -1.5707963267948966 + +-- branch points: +/-1 +acosh0010 acosh 1.0 0.0 -> 0.0 0.0 +acosh0011 acosh 1.0 -0.0 -> 0.0 -0.0 +acosh0012 acosh -1.0 0.0 -> 0.0 3.1415926535897931 +acosh0013 acosh -1.0 -0.0 -> 0.0 -3.1415926535897931 + +-- values along both sides of real axis +acosh0020 acosh -9.8813129168249309e-324 0.0 -> 0.0 1.5707963267948966 +acosh0021 acosh -9.8813129168249309e-324 -0.0 -> 0.0 -1.5707963267948966 +acosh0022 acosh -1e-305 0.0 -> 0.0 1.5707963267948966 +acosh0023 acosh -1e-305 -0.0 -> 0.0 -1.5707963267948966 +acosh0024 acosh -1e-150 0.0 -> 0.0 1.5707963267948966 +acosh0025 acosh -1e-150 -0.0 -> 0.0 -1.5707963267948966 +acosh0026 acosh -9.9999999999999998e-17 0.0 -> 0.0 1.5707963267948968 +acosh0027 acosh -9.9999999999999998e-17 -0.0 -> 0.0 -1.5707963267948968 +acosh0028 acosh -0.001 0.0 -> 0.0 1.5717963269615634 +acosh0029 acosh -0.001 -0.0 -> 0.0 -1.5717963269615634 +acosh0030 acosh -0.57899999999999996 0.0 -> 0.0 2.1882979816120667 +acosh0031 acosh -0.57899999999999996 -0.0 -> 0.0 -2.1882979816120667 +acosh0032 acosh -0.99999999999999989 0.0 -> 0.0 3.1415926386886319 +acosh0033 acosh -0.99999999999999989 -0.0 -> 0.0 -3.1415926386886319 +acosh0034 acosh -1.0000000000000002 0.0 -> 2.1073424255447014e-08 3.1415926535897931 +acosh0035 acosh -1.0000000000000002 -0.0 -> 2.1073424255447014e-08 -3.1415926535897931 +acosh0036 acosh -1.0009999999999999 0.0 -> 0.044717633608306849 3.1415926535897931 +acosh0037 acosh -1.0009999999999999 -0.0 -> 0.044717633608306849 -3.1415926535897931 +acosh0038 acosh -2.0 0.0 -> 1.3169578969248168 3.1415926535897931 +acosh0039 acosh -2.0 -0.0 -> 1.3169578969248168 -3.1415926535897931 +acosh0040 acosh -23.0 0.0 -> 3.8281684713331012 3.1415926535897931 +acosh0041 acosh -23.0 -0.0 -> 3.8281684713331012 -3.1415926535897931 +acosh0042 acosh -10000000000000000.0 0.0 -> 37.534508668464674 3.1415926535897931 +acosh0043 acosh -10000000000000000.0 -0.0 -> 37.534508668464674 -3.1415926535897931 +acosh0044 acosh -9.9999999999999998e+149 0.0 -> 346.08091112966679 3.1415926535897931 +acosh0045 acosh -9.9999999999999998e+149 -0.0 -> 346.08091112966679 -3.1415926535897931 +acosh0046 acosh -1.0000000000000001e+299 0.0 -> 689.16608998577965 3.1415926535897931 +acosh0047 acosh -1.0000000000000001e+299 -0.0 -> 689.16608998577965 -3.1415926535897931 +acosh0048 acosh 9.8813129168249309e-324 0.0 -> 0.0 1.5707963267948966 +acosh0049 acosh 9.8813129168249309e-324 -0.0 -> 0.0 -1.5707963267948966 +acosh0050 acosh 1e-305 0.0 -> 0.0 1.5707963267948966 +acosh0051 acosh 1e-305 -0.0 -> 0.0 -1.5707963267948966 +acosh0052 acosh 1e-150 0.0 -> 0.0 1.5707963267948966 +acosh0053 acosh 1e-150 -0.0 -> 0.0 -1.5707963267948966 +acosh0054 acosh 9.9999999999999998e-17 0.0 -> 0.0 1.5707963267948966 +acosh0055 acosh 9.9999999999999998e-17 -0.0 -> 0.0 -1.5707963267948966 +acosh0056 acosh 0.001 0.0 -> 0.0 1.56979632662823 +acosh0057 acosh 0.001 -0.0 -> 0.0 -1.56979632662823 +acosh0058 acosh 0.57899999999999996 0.0 -> 0.0 0.95329467197772655 +acosh0059 acosh 0.57899999999999996 -0.0 -> 0.0 -0.95329467197772655 +acosh0060 acosh 0.99999999999999989 0.0 -> 0.0 1.4901161193847656e-08 +acosh0061 acosh 0.99999999999999989 -0.0 -> 0.0 -1.4901161193847656e-08 +acosh0062 acosh 1.0000000000000002 0.0 -> 2.1073424255447014e-08 0.0 +acosh0063 acosh 1.0000000000000002 -0.0 -> 2.1073424255447014e-08 -0.0 +acosh0064 acosh 1.0009999999999999 0.0 -> 0.044717633608306849 0.0 +acosh0065 acosh 1.0009999999999999 -0.0 -> 0.044717633608306849 -0.0 +acosh0066 acosh 2.0 0.0 -> 1.3169578969248168 0.0 +acosh0067 acosh 2.0 -0.0 -> 1.3169578969248168 -0.0 +acosh0068 acosh 23.0 0.0 -> 3.8281684713331012 0.0 +acosh0069 acosh 23.0 -0.0 -> 3.8281684713331012 -0.0 +acosh0070 acosh 10000000000000000.0 0.0 -> 37.534508668464674 0.0 +acosh0071 acosh 10000000000000000.0 -0.0 -> 37.534508668464674 -0.0 +acosh0072 acosh 9.9999999999999998e+149 0.0 -> 346.08091112966679 0.0 +acosh0073 acosh 9.9999999999999998e+149 -0.0 -> 346.08091112966679 -0.0 +acosh0074 acosh 1.0000000000000001e+299 0.0 -> 689.16608998577965 0.0 +acosh0075 acosh 1.0000000000000001e+299 -0.0 -> 689.16608998577965 -0.0 + +-- random inputs +acosh0100 acosh -1.4328589581250843 -1.8370347775558309 -> 1.5526962646549587 -2.190250168435786 +acosh0101 acosh -0.31075819156220957 -1.0772555786839297 -> 0.95139168286193709 -1.7812228089636479 +acosh0102 acosh -1.9044776578070453 -20.485370158932124 -> 3.7177411088932359 -1.6633888745861227 +acosh0103 acosh -0.075642506000858742 -21965976320.873051 -> 24.505907742881991 -1.5707963267983402 +acosh0104 acosh -1.6162271181056307 -3.0369343458696099 -> 1.9407057262861227 -2.0429549461750209 +acosh0105 acosh -0.3103780280298063 0.00018054880018078987 -> 0.00018992877058761416 1.886386995096728 +acosh0106 acosh -9159468751.5897655 5.8014747664273649 -> 23.631201197959193 3.1415926529564078 +acosh0107 acosh -0.037739157550933884 0.21841357493510705 -> 0.21685844960602488 1.6076735133449402 +acosh0108 acosh -8225991.0508394297 0.28318543008913644 -> 16.615956520420287 3.1415926191641019 +acosh0109 acosh -35.620070502302639 0.31303237005015 -> 4.2658980006943965 3.1328013255541873 +acosh0110 acosh 96.729939906820917 -0.029345228372365334 -> 5.2650434775863548 -0.00030338895866972843 +acosh0111 acosh 0.59656024007966491 -2.0412294654163978 -> 1.4923002024287835 -1.312568421900338 +acosh0112 acosh 109.29384112677828 -0.00015454863061533812 -> 5.3871662961545477 -1.4141245154061214e-06 +acosh0113 acosh 8.6705651969361597 -3.6723631649787465 -> 2.9336180958363545 -0.40267362031872861 +acosh0114 acosh 1.8101646445052686 -0.012345132721855478 -> 1.1997148566285769 -0.0081813912760150265 +acosh0115 acosh 52.56897195025288 0.001113916065985443 -> 4.6551827622264135 2.1193445872040307e-05 +acosh0116 acosh 0.28336786164214739 355643992457.40485 -> 27.290343226816528 1.5707963267940999 +acosh0117 acosh 0.73876621291911437 2.8828594541104322e-20 -> 4.2774820978159067e-20 0.73955845836827927 +acosh0118 acosh 0.025865471781718878 37125746064318.492 -> 31.938478989418012 1.5707963267948959 +acosh0119 acosh 2.2047353511780132 0.074712248143489271 -> 1.4286403248698021 0.037997904971626598 + +-- values near infinity +acosh0200 acosh 8.1548592876467785e+307 9.0943779335951128e+307 -> 710.08944620800605 0.83981165425478954 +acosh0201 acosh 1.4237229680972531e+308 -1.0336966617874858e+308 -> 710.4543331094759 -0.6279972876348755 +acosh0202 acosh -1.5014526899738939e+308 1.5670700378448792e+308 -> 710.66420706795464 2.3348137299106697 +acosh0203 acosh -1.0939040375213928e+308 -1.0416960351127978e+308 -> 710.30182863115886 -2.380636147787027 +acosh0204 acosh 0.0 1.476062433559588e+308 -> 710.27873384716929 1.5707963267948966 +acosh0205 acosh -0.0 6.2077210326221094e+307 -> 709.41256457484769 1.5707963267948966 +acosh0206 acosh 0.0 -1.5621899909968308e+308 -> 710.33544449990734 -1.5707963267948966 +acosh0207 acosh -0.0 -8.3556624833839122e+307 -> 709.70971018048317 -1.5707963267948966 +acosh0208 acosh 1.3067079752499342e+308 0.0 -> 710.15686680107228 0.0 +acosh0209 acosh 1.5653640340214026e+308 -0.0 -> 710.33747422926706 -0.0 +acosh0210 acosh -6.9011375992290636e+307 0.0 -> 709.51845699719922 3.1415926535897931 +acosh0211 acosh -9.9539576809926973e+307 -0.0 -> 709.88474095870185 -3.1415926535897931 +acosh0212 acosh 7.6449598518914925e+307 9.5706540768268358 -> 709.62081731754802 1.2518906916769345e-307 +acosh0213 acosh 5.4325410972602197e+307 -7.8064807816522706 -> 709.279177727925 -1.4369851312471974e-307 +acosh0214 acosh -1.1523626112360465e+308 7.0617510038869336 -> 710.03117010216909 3.1415926535897931 +acosh0215 acosh -1.1685027786862599e+308 -5.1568558357925625 -> 710.04507907571417 -3.1415926535897931 +acosh0216 acosh 3.0236370339788721 1.7503248720096417e+308 -> 710.44915723458064 1.5707963267948966 +acosh0217 acosh 6.6108007926031149 -9.1469968225806149e+307 -> 709.80019633903328 -1.5707963267948966 +acosh0218 acosh -5.1096262905623959 6.4484926785412395e+307 -> 709.45061713997973 1.5707963267948966 +acosh0219 acosh -2.8080920608735846 -1.7716118836519368e+308 -> 710.46124562363445 -1.5707963267948966 + +-- values near 0 +acosh0220 acosh 4.5560530326699304e-317 7.3048989121436657e-318 -> 7.3048989121436657e-318 1.5707963267948966 +acosh0221 acosh 4.8754274133585331e-314 -9.8469794897684199e-315 -> 9.8469794897684199e-315 -1.5707963267948966 +acosh0222 acosh -4.6748876009960097e-312 9.7900342887557606e-318 -> 9.7900342887557606e-318 1.5707963267948966 +acosh0223 acosh -4.3136871538399236e-320 -4.9406564584124654e-323 -> 4.9406564584124654e-323 -1.5707963267948966 +acosh0224 acosh 0.0 4.3431013866496774e-314 -> 4.3431013866496774e-314 1.5707963267948966 +acosh0225 acosh -0.0 6.0147334335829184e-317 -> 6.0147334335829184e-317 1.5707963267948966 +acosh0226 acosh 0.0 -1.2880291387081297e-320 -> 1.2880291387081297e-320 -1.5707963267948966 +acosh0227 acosh -0.0 -1.4401563976534621e-317 -> 1.4401563976534621e-317 -1.5707963267948966 +acosh0228 acosh 1.3689680570863091e-313 0.0 -> 0.0 1.5707963267948966 +acosh0229 acosh 1.5304346893494371e-312 -0.0 -> 0.0 -1.5707963267948966 +acosh0230 acosh -3.7450175954766488e-320 0.0 -> 0.0 1.5707963267948966 +acosh0231 acosh -8.4250563080885801e-311 -0.0 -> 0.0 -1.5707963267948966 + +-- special values +acosh1000 acosh 0.0 0.0 -> 0.0 1.5707963267948966 +acosh1001 acosh -0.0 0.0 -> 0.0 1.5707963267948966 +acosh1002 acosh 0.0 inf -> inf 1.5707963267948966 +acosh1003 acosh 2.3 inf -> inf 1.5707963267948966 +acosh1004 acosh -0.0 inf -> inf 1.5707963267948966 +acosh1005 acosh -2.3 inf -> inf 1.5707963267948966 +acosh1006 acosh 0.0 nan -> nan nan +acosh1007 acosh 2.3 nan -> nan nan +acosh1008 acosh -0.0 nan -> nan nan +acosh1009 acosh -2.3 nan -> nan nan +acosh1010 acosh -inf 0.0 -> inf 3.1415926535897931 +acosh1011 acosh -inf 2.3 -> inf 3.1415926535897931 +acosh1012 acosh inf 0.0 -> inf 0.0 +acosh1013 acosh inf 2.3 -> inf 0.0 +acosh1014 acosh -inf inf -> inf 2.3561944901923448 +acosh1015 acosh inf inf -> inf 0.78539816339744828 +acosh1016 acosh inf nan -> inf nan +acosh1017 acosh -inf nan -> inf nan +acosh1018 acosh nan 0.0 -> nan nan +acosh1019 acosh nan 2.3 -> nan nan +acosh1020 acosh nan inf -> inf nan +acosh1021 acosh nan nan -> nan nan +acosh1022 acosh 0.0 -0.0 -> 0.0 -1.5707963267948966 +acosh1023 acosh -0.0 -0.0 -> 0.0 -1.5707963267948966 +acosh1024 acosh 0.0 -inf -> inf -1.5707963267948966 +acosh1025 acosh 2.3 -inf -> inf -1.5707963267948966 +acosh1026 acosh -0.0 -inf -> inf -1.5707963267948966 +acosh1027 acosh -2.3 -inf -> inf -1.5707963267948966 +acosh1028 acosh -inf -0.0 -> inf -3.1415926535897931 +acosh1029 acosh -inf -2.3 -> inf -3.1415926535897931 +acosh1030 acosh inf -0.0 -> inf -0.0 +acosh1031 acosh inf -2.3 -> inf -0.0 +acosh1032 acosh -inf -inf -> inf -2.3561944901923448 +acosh1033 acosh inf -inf -> inf -0.78539816339744828 +acosh1034 acosh nan -0.0 -> nan nan +acosh1035 acosh nan -2.3 -> nan nan +acosh1036 acosh nan -inf -> inf nan + + +------------------------ +-- asin: Inverse sine -- +------------------------ + +-- zeros +asin0000 asin 0.0 0.0 -> 0.0 0.0 +asin0001 asin 0.0 -0.0 -> 0.0 -0.0 +asin0002 asin -0.0 0.0 -> -0.0 0.0 +asin0003 asin -0.0 -0.0 -> -0.0 -0.0 + +-- branch points: +/-1 +asin0010 asin 1.0 0.0 -> 1.5707963267948966 0.0 +asin0011 asin 1.0 -0.0 -> 1.5707963267948966 -0.0 +asin0012 asin -1.0 0.0 -> -1.5707963267948966 0.0 +asin0013 asin -1.0 -0.0 -> -1.5707963267948966 -0.0 + +-- values along both sides of real axis +asin0020 asin -9.8813129168249309e-324 0.0 -> -9.8813129168249309e-324 0.0 +asin0021 asin -9.8813129168249309e-324 -0.0 -> -9.8813129168249309e-324 -0.0 +asin0022 asin -1e-305 0.0 -> -1e-305 0.0 +asin0023 asin -1e-305 -0.0 -> -1e-305 -0.0 +asin0024 asin -1e-150 0.0 -> -1e-150 0.0 +asin0025 asin -1e-150 -0.0 -> -1e-150 -0.0 +asin0026 asin -9.9999999999999998e-17 0.0 -> -9.9999999999999998e-17 0.0 +asin0027 asin -9.9999999999999998e-17 -0.0 -> -9.9999999999999998e-17 -0.0 +asin0028 asin -0.001 0.0 -> -0.0010000001666667416 0.0 +asin0029 asin -0.001 -0.0 -> -0.0010000001666667416 -0.0 +asin0030 asin -0.57899999999999996 0.0 -> -0.61750165481717001 0.0 +asin0031 asin -0.57899999999999996 -0.0 -> -0.61750165481717001 -0.0 +asin0032 asin -0.99999999999999989 0.0 -> -1.5707963118937354 0.0 +asin0033 asin -0.99999999999999989 -0.0 -> -1.5707963118937354 -0.0 +asin0034 asin -1.0000000000000002 0.0 -> -1.5707963267948966 2.1073424255447014e-08 +asin0035 asin -1.0000000000000002 -0.0 -> -1.5707963267948966 -2.1073424255447014e-08 +asin0036 asin -1.0009999999999999 0.0 -> -1.5707963267948966 0.044717633608306849 +asin0037 asin -1.0009999999999999 -0.0 -> -1.5707963267948966 -0.044717633608306849 +asin0038 asin -2.0 0.0 -> -1.5707963267948966 1.3169578969248168 +asin0039 asin -2.0 -0.0 -> -1.5707963267948966 -1.3169578969248168 +asin0040 asin -23.0 0.0 -> -1.5707963267948966 3.8281684713331012 +asin0041 asin -23.0 -0.0 -> -1.5707963267948966 -3.8281684713331012 +asin0042 asin -10000000000000000.0 0.0 -> -1.5707963267948966 37.534508668464674 +asin0043 asin -10000000000000000.0 -0.0 -> -1.5707963267948966 -37.534508668464674 +asin0044 asin -9.9999999999999998e+149 0.0 -> -1.5707963267948966 346.08091112966679 +asin0045 asin -9.9999999999999998e+149 -0.0 -> -1.5707963267948966 -346.08091112966679 +asin0046 asin -1.0000000000000001e+299 0.0 -> -1.5707963267948966 689.16608998577965 +asin0047 asin -1.0000000000000001e+299 -0.0 -> -1.5707963267948966 -689.16608998577965 +asin0048 asin 9.8813129168249309e-324 0.0 -> 9.8813129168249309e-324 0.0 +asin0049 asin 9.8813129168249309e-324 -0.0 -> 9.8813129168249309e-324 -0.0 +asin0050 asin 1e-305 0.0 -> 1e-305 0.0 +asin0051 asin 1e-305 -0.0 -> 1e-305 -0.0 +asin0052 asin 1e-150 0.0 -> 1e-150 0.0 +asin0053 asin 1e-150 -0.0 -> 1e-150 -0.0 +asin0054 asin 9.9999999999999998e-17 0.0 -> 9.9999999999999998e-17 0.0 +asin0055 asin 9.9999999999999998e-17 -0.0 -> 9.9999999999999998e-17 -0.0 +asin0056 asin 0.001 0.0 -> 0.0010000001666667416 0.0 +asin0057 asin 0.001 -0.0 -> 0.0010000001666667416 -0.0 +asin0058 asin 0.57899999999999996 0.0 -> 0.61750165481717001 0.0 +asin0059 asin 0.57899999999999996 -0.0 -> 0.61750165481717001 -0.0 +asin0060 asin 0.99999999999999989 0.0 -> 1.5707963118937354 0.0 +asin0061 asin 0.99999999999999989 -0.0 -> 1.5707963118937354 -0.0 +asin0062 asin 1.0000000000000002 0.0 -> 1.5707963267948966 2.1073424255447014e-08 +asin0063 asin 1.0000000000000002 -0.0 -> 1.5707963267948966 -2.1073424255447014e-08 +asin0064 asin 1.0009999999999999 0.0 -> 1.5707963267948966 0.044717633608306849 +asin0065 asin 1.0009999999999999 -0.0 -> 1.5707963267948966 -0.044717633608306849 +asin0066 asin 2.0 0.0 -> 1.5707963267948966 1.3169578969248168 +asin0067 asin 2.0 -0.0 -> 1.5707963267948966 -1.3169578969248168 +asin0068 asin 23.0 0.0 -> 1.5707963267948966 3.8281684713331012 +asin0069 asin 23.0 -0.0 -> 1.5707963267948966 -3.8281684713331012 +asin0070 asin 10000000000000000.0 0.0 -> 1.5707963267948966 37.534508668464674 +asin0071 asin 10000000000000000.0 -0.0 -> 1.5707963267948966 -37.534508668464674 +asin0072 asin 9.9999999999999998e+149 0.0 -> 1.5707963267948966 346.08091112966679 +asin0073 asin 9.9999999999999998e+149 -0.0 -> 1.5707963267948966 -346.08091112966679 +asin0074 asin 1.0000000000000001e+299 0.0 -> 1.5707963267948966 689.16608998577965 +asin0075 asin 1.0000000000000001e+299 -0.0 -> 1.5707963267948966 -689.16608998577965 + +-- random inputs +asin0100 asin -1.5979555835086083 -0.15003009814595247 -> -1.4515369557405788 -1.0544476399790823 +asin0101 asin -0.57488225895317679 -9.6080397838952743e-13 -> -0.61246024460412851 -1.174238005400403e-12 +asin0102 asin -3.6508087930516249 -0.36027527093220152 -> -1.4685890605305874 -1.9742273007152038 +asin0103 asin -1.5238659792326819 -1.1360813516996364 -> -0.86080051691147275 -1.3223742205689195 +asin0104 asin -1592.0639045555306 -0.72362427935018236 -> -1.5703418071175179 -8.0659336918729228 +asin0105 asin -0.19835471371312019 4.2131508416697709 -> -0.045777831019935149 2.1461732751933171 +asin0106 asin -1.918471054430213 0.40603305079779234 -> -1.3301396585791556 1.30263642314981 +asin0107 asin -254495.01623373642 0.71084414434470822 -> -1.5707935336394359 13.140183712762321 +asin0108 asin -0.31315882715691157 3.9647994288429866 -> -0.076450403840916004 2.0889762138713457 +asin0109 asin -0.90017064284720816 1.2530659485907105 -> -0.53466509741943447 1.1702811557577 +asin0110 asin 2.1615181696571075 -0.14058647488229523 -> 1.4976166323896871 -1.4085811039334604 +asin0111 asin 1.2104749210707795 -0.85732484485298999 -> 0.83913071588343924 -1.0681719250525901 +asin0112 asin 1.7059733185128891 -0.84032966373156581 -> 1.0510900815816229 -1.2967979791361652 +asin0113 asin 9.9137085017290687 -1.4608383970250893 -> 1.4237704820128891 -2.995414677560686 +asin0114 asin 117.12344751041495 -5453908091.5334015 -> 2.1475141411392012e-08 -23.112745450217066 +asin0115 asin 0.081041187798029227 0.067054349860173196 -> 0.080946786856771813 0.067223991060639698 +asin0116 asin 46.635472322049949 2.3835190718056678 -> 1.5197194940010779 4.5366989600972083 +asin0117 asin 3907.0687961127105 19.144021886390181 -> 1.5658965233083235 8.9637018715924217 +asin0118 asin 1.0889312322308273 509.01577883554768 -> 0.0021392803817829316 6.9256294494524706 +asin0119 asin 0.10851518277509224 1.5612510908217476 -> 0.058491014243902621 1.2297075725621327 + +-- values near infinity +asin0200 asin 1.5230241998821499e+308 5.5707228994084525e+307 -> 1.2201446370892068 710.37283486535966 +asin0201 asin 8.1334317698672204e+307 -9.2249425197872451e+307 -> 0.72259991284020042 -710.0962453049026 +asin0202 asin -9.9138506659241768e+307 6.701544526434995e+307 -> -0.97637511742194594 710.06887486671371 +asin0203 asin -1.4141298868173842e+308 -5.401505134514191e+307 -> -1.2059319055160587 -710.30396478954628 +asin0204 asin 0.0 9.1618092977897431e+307 -> 0.0 709.80181441050593 +asin0205 asin -0.0 6.8064342551939755e+307 -> -0.0 709.50463910853489 +asin0206 asin 0.0 -6.4997516454798215e+307 -> 0.0 -709.45853469751592 +asin0207 asin -0.0 -1.6767449053345242e+308 -> -0.0 -710.4062101803022 +asin0208 asin 5.4242749957378916e+307 0.0 -> 1.5707963267948966 709.27765497888902 +asin0209 asin 9.5342145121164749e+307 -0.0 -> 1.5707963267948966 -709.84165758595907 +asin0210 asin -7.0445698006201847e+307 0.0 -> -1.5707963267948966 709.53902780872136 +asin0211 asin -1.0016025569769706e+308 -0.0 -> -1.5707963267948966 -709.89095709697881 +asin0212 asin 1.6552203778877204e+308 0.48761543336249491 -> 1.5707963267948966 710.39328998153474 +asin0213 asin 1.2485712830384869e+308 -4.3489311161278899 -> 1.5707963267948966 -710.1113557467786 +asin0214 asin -1.5117842813353125e+308 5.123452666102434 -> -1.5707963267948966 710.30264641923031 +asin0215 asin -1.3167634313008016e+308 -0.52939679793528982 -> -1.5707963267948966 -710.16453260239768 +asin0216 asin 0.80843929176985907 1.0150851827767876e+308 -> 7.9642507396113875e-309 709.90432835561637 +asin0217 asin 8.2544809829680901 -1.7423548140539474e+308 -> 4.7375430746865733e-308 -710.44459336242164 +asin0218 asin -5.2499000118824295 4.6655578977512214e+307 -> -1.1252459249113292e-307 709.1269781491103 +asin0219 asin -5.9904782760833433 -4.7315689314781163e+307 -> -1.2660659419394637e-307 -709.14102757522312 + +-- special values +asin1000 asin -0.0 0.0 -> -0.0 0.0 +asin1001 asin 0.0 0.0 -> 0.0 0.0 +asin1002 asin -0.0 -0.0 -> -0.0 -0.0 +asin1003 asin 0.0 -0.0 -> 0.0 -0.0 +asin1004 asin -inf 0.0 -> -1.5707963267948966 inf +asin1005 asin -inf 2.2999999999999998 -> -1.5707963267948966 inf +asin1006 asin nan 0.0 -> nan nan +asin1007 asin nan 2.2999999999999998 -> nan nan +asin1008 asin -0.0 inf -> -0.0 inf +asin1009 asin -2.2999999999999998 inf -> -0.0 inf +asin1010 asin -inf inf -> -0.78539816339744828 inf +asin1011 asin nan inf -> nan inf +asin1012 asin -0.0 nan -> -0.0 nan +asin1013 asin -2.2999999999999998 nan -> nan nan +asin1014 asin -inf nan -> nan inf ignore-imag-sign +asin1015 asin nan nan -> nan nan +asin1016 asin inf 0.0 -> 1.5707963267948966 inf +asin1017 asin inf 2.2999999999999998 -> 1.5707963267948966 inf +asin1018 asin 0.0 inf -> 0.0 inf +asin1019 asin 2.2999999999999998 inf -> 0.0 inf +asin1020 asin inf inf -> 0.78539816339744828 inf +asin1021 asin 0.0 nan -> 0.0 nan +asin1022 asin 2.2999999999999998 nan -> nan nan +asin1023 asin inf nan -> nan inf ignore-imag-sign +asin1024 asin inf -0.0 -> 1.5707963267948966 -inf +asin1025 asin inf -2.2999999999999998 -> 1.5707963267948966 -inf +asin1026 asin nan -0.0 -> nan nan +asin1027 asin nan -2.2999999999999998 -> nan nan +asin1028 asin 0.0 -inf -> 0.0 -inf +asin1029 asin 2.2999999999999998 -inf -> 0.0 -inf +asin1030 asin inf -inf -> 0.78539816339744828 -inf +asin1031 asin nan -inf -> nan -inf +asin1032 asin -inf -0.0 -> -1.5707963267948966 -inf +asin1033 asin -inf -2.2999999999999998 -> -1.5707963267948966 -inf +asin1034 asin -0.0 -inf -> -0.0 -inf +asin1035 asin -2.2999999999999998 -inf -> -0.0 -inf +asin1036 asin -inf -inf -> -0.78539816339744828 -inf + + +------------------------------------ +-- asinh: Inverse hyperbolic sine -- +------------------------------------ + +-- zeros +asinh0000 asinh 0.0 0.0 -> 0.0 0.0 +asinh0001 asinh 0.0 -0.0 -> 0.0 -0.0 +asinh0002 asinh -0.0 0.0 -> -0.0 0.0 +asinh0003 asinh -0.0 -0.0 -> -0.0 -0.0 + +-- branch points: +/-i +asinh0010 asinh 0.0 1.0 -> 0.0 1.5707963267948966 +asinh0011 asinh 0.0 -1.0 -> 0.0 -1.5707963267948966 +asinh0012 asinh -0.0 1.0 -> -0.0 1.5707963267948966 +asinh0013 asinh -0.0 -1.0 -> -0.0 -1.5707963267948966 + +-- values along both sides of imaginary axis +asinh0020 asinh 0.0 -9.8813129168249309e-324 -> 0.0 -9.8813129168249309e-324 +asinh0021 asinh -0.0 -9.8813129168249309e-324 -> -0.0 -9.8813129168249309e-324 +asinh0022 asinh 0.0 -1e-305 -> 0.0 -1e-305 +asinh0023 asinh -0.0 -1e-305 -> -0.0 -1e-305 +asinh0024 asinh 0.0 -1e-150 -> 0.0 -1e-150 +asinh0025 asinh -0.0 -1e-150 -> -0.0 -1e-150 +asinh0026 asinh 0.0 -9.9999999999999998e-17 -> 0.0 -9.9999999999999998e-17 +asinh0027 asinh -0.0 -9.9999999999999998e-17 -> -0.0 -9.9999999999999998e-17 +asinh0028 asinh 0.0 -0.001 -> 0.0 -0.0010000001666667416 +asinh0029 asinh -0.0 -0.001 -> -0.0 -0.0010000001666667416 +asinh0030 asinh 0.0 -0.57899999999999996 -> 0.0 -0.61750165481717001 +asinh0031 asinh -0.0 -0.57899999999999996 -> -0.0 -0.61750165481717001 +asinh0032 asinh 0.0 -0.99999999999999989 -> 0.0 -1.5707963118937354 +asinh0033 asinh -0.0 -0.99999999999999989 -> -0.0 -1.5707963118937354 +asinh0034 asinh 0.0 -1.0000000000000002 -> 2.1073424255447014e-08 -1.5707963267948966 +asinh0035 asinh -0.0 -1.0000000000000002 -> -2.1073424255447014e-08 -1.5707963267948966 +asinh0036 asinh 0.0 -1.0009999999999999 -> 0.044717633608306849 -1.5707963267948966 +asinh0037 asinh -0.0 -1.0009999999999999 -> -0.044717633608306849 -1.5707963267948966 +asinh0038 asinh 0.0 -2.0 -> 1.3169578969248168 -1.5707963267948966 +asinh0039 asinh -0.0 -2.0 -> -1.3169578969248168 -1.5707963267948966 +asinh0040 asinh 0.0 -20.0 -> 3.6882538673612966 -1.5707963267948966 +asinh0041 asinh -0.0 -20.0 -> -3.6882538673612966 -1.5707963267948966 +asinh0042 asinh 0.0 -10000000000000000.0 -> 37.534508668464674 -1.5707963267948966 +asinh0043 asinh -0.0 -10000000000000000.0 -> -37.534508668464674 -1.5707963267948966 +asinh0044 asinh 0.0 -9.9999999999999998e+149 -> 346.08091112966679 -1.5707963267948966 +asinh0045 asinh -0.0 -9.9999999999999998e+149 -> -346.08091112966679 -1.5707963267948966 +asinh0046 asinh 0.0 -1.0000000000000001e+299 -> 689.16608998577965 -1.5707963267948966 +asinh0047 asinh -0.0 -1.0000000000000001e+299 -> -689.16608998577965 -1.5707963267948966 +asinh0048 asinh 0.0 9.8813129168249309e-324 -> 0.0 9.8813129168249309e-324 +asinh0049 asinh -0.0 9.8813129168249309e-324 -> -0.0 9.8813129168249309e-324 +asinh0050 asinh 0.0 1e-305 -> 0.0 1e-305 +asinh0051 asinh -0.0 1e-305 -> -0.0 1e-305 +asinh0052 asinh 0.0 1e-150 -> 0.0 1e-150 +asinh0053 asinh -0.0 1e-150 -> -0.0 1e-150 +asinh0054 asinh 0.0 9.9999999999999998e-17 -> 0.0 9.9999999999999998e-17 +asinh0055 asinh -0.0 9.9999999999999998e-17 -> -0.0 9.9999999999999998e-17 +asinh0056 asinh 0.0 0.001 -> 0.0 0.0010000001666667416 +asinh0057 asinh -0.0 0.001 -> -0.0 0.0010000001666667416 +asinh0058 asinh 0.0 0.57899999999999996 -> 0.0 0.61750165481717001 +asinh0059 asinh -0.0 0.57899999999999996 -> -0.0 0.61750165481717001 +asinh0060 asinh 0.0 0.99999999999999989 -> 0.0 1.5707963118937354 +asinh0061 asinh -0.0 0.99999999999999989 -> -0.0 1.5707963118937354 +asinh0062 asinh 0.0 1.0000000000000002 -> 2.1073424255447014e-08 1.5707963267948966 +asinh0063 asinh -0.0 1.0000000000000002 -> -2.1073424255447014e-08 1.5707963267948966 +asinh0064 asinh 0.0 1.0009999999999999 -> 0.044717633608306849 1.5707963267948966 +asinh0065 asinh -0.0 1.0009999999999999 -> -0.044717633608306849 1.5707963267948966 +asinh0066 asinh 0.0 2.0 -> 1.3169578969248168 1.5707963267948966 +asinh0067 asinh -0.0 2.0 -> -1.3169578969248168 1.5707963267948966 +asinh0068 asinh 0.0 20.0 -> 3.6882538673612966 1.5707963267948966 +asinh0069 asinh -0.0 20.0 -> -3.6882538673612966 1.5707963267948966 +asinh0070 asinh 0.0 10000000000000000.0 -> 37.534508668464674 1.5707963267948966 +asinh0071 asinh -0.0 10000000000000000.0 -> -37.534508668464674 1.5707963267948966 +asinh0072 asinh 0.0 9.9999999999999998e+149 -> 346.08091112966679 1.5707963267948966 +asinh0073 asinh -0.0 9.9999999999999998e+149 -> -346.08091112966679 1.5707963267948966 +asinh0074 asinh 0.0 1.0000000000000001e+299 -> 689.16608998577965 1.5707963267948966 +asinh0075 asinh -0.0 1.0000000000000001e+299 -> -689.16608998577965 1.5707963267948966 + +-- random inputs +asinh0100 asinh -0.5946402853710423 -0.044506548910000145 -> -0.56459775392653022 -0.038256221441536356 +asinh0101 asinh -0.19353958046180916 -0.017489624793193454 -> -0.19237926804196651 -0.017171741895336792 +asinh0102 asinh -0.033117585138955893 -8.5256414015933757 -> -2.8327758348650969 -1.5668848791092411 +asinh0103 asinh -1.5184043184035716 -0.73491245339073275 -> -1.2715891419764005 -0.39204624408542355 +asinh0104 asinh -0.60716120271208818 -0.28900743958436542 -> -0.59119299421187232 -0.24745931678118135 +asinh0105 asinh -0.0237177865112429 2.8832601052166313 -> -1.7205820772413236 1.5620261702963094 +asinh0106 asinh -2.3906812342743979 2.6349216848574013 -> -1.9609636249445124 0.8142142660574706 +asinh0107 asinh -0.0027605019787620517 183.85588476550555 -> -5.9072920005445066 1.5707813120847871 +asinh0108 asinh -0.99083661164404713 0.028006797051617648 -> -0.8750185251283995 0.019894099615994653 +asinh0109 asinh -3.0362951937986393 0.86377266758504867 -> -1.8636030714685221 0.26475058859950168 +asinh0110 asinh 0.34438464536152769 -0.71603790174885029 -> 0.43985415690734164 -0.71015037409294324 +asinh0111 asinh 4.4925124413876256 -60604595352.871613 -> 25.520783738612078 -1.5707963267207683 +asinh0112 asinh 2.3213991428170337 -7.5459667007307258 -> 2.7560464993451643 -1.270073210856117 +asinh0113 asinh 0.21291939741682028 -1.2720428814784408 -> 0.77275088137338266 -1.3182099250896895 +asinh0114 asinh 6.6447359379455957 -0.97196191666946996 -> 2.602830695139672 -0.14368247412319965 +asinh0115 asinh 7.1326256655083746 2.1516360452706857 -> 2.7051146374367212 0.29051701669727581 +asinh0116 asinh 0.18846550905063442 3.4705348585339832 -> 1.917697875799296 1.514155593347924 +asinh0117 asinh 0.19065075303281598 0.26216814548222012 -> 0.19603050785932474 0.26013422809614117 +asinh0118 asinh 2.0242004665739719 0.70510281647495787 -> 1.4970366212896002 0.30526007200481453 +asinh0119 asinh 37.336596461576057 717.29157391678234 -> 7.269981997945294 1.5187910219576033 + +-- values near infinity +asinh0200 asinh 1.0760517500874541e+308 1.1497786241240167e+308 -> 710.34346055651815 0.81850936961793475 +asinh0201 asinh 1.1784839328845529e+308 -1.6478429586716638e+308 -> 710.59536255783678 -0.94996311735607697 +asinh0202 asinh -4.8777682248909193e+307 1.4103736217538474e+308 -> -710.28970147376992 1.2378239519096443 +asinh0203 asinh -1.2832478903233108e+308 -1.5732392613155698e+308 -> -710.59750164290745 -0.88657181439322452 +asinh0204 asinh 0.0 6.8431383856345372e+307 -> 709.51001718444604 1.5707963267948966 +asinh0205 asinh -0.0 8.601822432238051e+307 -> -709.73874482126689 1.5707963267948966 +asinh0206 asinh 0.0 -5.5698396067303782e+307 -> 709.30413698733742 -1.5707963267948966 +asinh0207 asinh -0.0 -7.1507777734621804e+307 -> -709.55399186002705 -1.5707963267948966 +asinh0208 asinh 1.6025136110019349e+308 0.0 -> 710.3609292261076 0.0 +asinh0209 asinh 1.3927819858239114e+308 -0.0 -> 710.22065899832899 -0.0 +asinh0210 asinh -6.0442994056210995e+307 0.0 -> -709.38588631057621 0.0 +asinh0211 asinh -1.2775271979042634e+308 -0.0 -> -710.13428215553972 -0.0 +asinh0212 asinh 1.0687496260268489e+308 1.0255615699476961 -> 709.95584521407841 9.5959010882679093e-309 +asinh0213 asinh 1.0050967333370962e+308 -0.87668970117333433 -> 709.89443961168183 -8.7224410556242882e-309 +asinh0214 asinh -5.7161452814862392e+307 8.2377808413450122 -> -709.33006540611166 1.4411426644501116e-307 +asinh0215 asinh -8.2009040727653315e+307 -6.407409526654976 -> -709.69101513070109 -7.8130526461510088e-308 +asinh0216 asinh 6.4239368496483982 1.6365990821551427e+308 -> 710.38197618101287 1.5707963267948966 +asinh0217 asinh 5.4729111423315882 -1.1227237438144211e+308 -> 710.00511346983546 -1.5707963267948966 +asinh0218 asinh -8.3455818297412723 1.443172020182019e+308 -> -710.25619930551818 1.5707963267948966 +asinh0219 asinh -2.6049726230372441 -1.7952291144022702e+308 -> -710.47448847685644 -1.5707963267948966 + +-- values near 0 +asinh0220 asinh 1.2940113339664088e-314 6.9169190417774516e-323 -> 1.2940113339664088e-314 6.9169190417774516e-323 +asinh0221 asinh 2.3848478863874649e-315 -3.1907655025717717e-310 -> 2.3848478863874649e-315 -3.1907655025717717e-310 +asinh0222 asinh -3.0097643679641622e-316 4.6936236354918422e-322 -> -3.0097643679641622e-316 4.6936236354918422e-322 +asinh0223 asinh -1.787997087755751e-308 -8.5619622834902341e-310 -> -1.787997087755751e-308 -8.5619622834902341e-310 +asinh0224 asinh 0.0 1.2491433448427325e-314 -> 0.0 1.2491433448427325e-314 +asinh0225 asinh -0.0 2.5024072154538062e-308 -> -0.0 2.5024072154538062e-308 +asinh0226 asinh 0.0 -2.9643938750474793e-323 -> 0.0 -2.9643938750474793e-323 +asinh0227 asinh -0.0 -2.9396905927554169e-320 -> -0.0 -2.9396905927554169e-320 +asinh0228 asinh 5.64042930029359e-317 0.0 -> 5.64042930029359e-317 0.0 +asinh0229 asinh 3.3833911866596068e-318 -0.0 -> 3.3833911866596068e-318 -0.0 +asinh0230 asinh -4.9406564584124654e-324 0.0 -> -4.9406564584124654e-324 0.0 +asinh0231 asinh -2.2211379227994845e-308 -0.0 -> -2.2211379227994845e-308 -0.0 + +-- special values +asinh1000 asinh 0.0 0.0 -> 0.0 0.0 +asinh1001 asinh 0.0 -0.0 -> 0.0 -0.0 +asinh1002 asinh -0.0 0.0 -> -0.0 0.0 +asinh1003 asinh -0.0 -0.0 -> -0.0 -0.0 +asinh1004 asinh 0.0 inf -> inf 1.5707963267948966 +asinh1005 asinh 2.3 inf -> inf 1.5707963267948966 +asinh1006 asinh 0.0 nan -> nan nan +asinh1007 asinh 2.3 nan -> nan nan +asinh1008 asinh inf 0.0 -> inf 0.0 +asinh1009 asinh inf 2.3 -> inf 0.0 +asinh1010 asinh inf inf -> inf 0.78539816339744828 +asinh1011 asinh inf nan -> inf nan +asinh1012 asinh nan 0.0 -> nan 0.0 +asinh1013 asinh nan 2.3 -> nan nan +asinh1014 asinh nan inf -> inf nan ignore-real-sign +asinh1015 asinh nan nan -> nan nan +asinh1016 asinh 0.0 -inf -> inf -1.5707963267948966 +asinh1017 asinh 2.3 -inf -> inf -1.5707963267948966 +asinh1018 asinh inf -0.0 -> inf -0.0 +asinh1019 asinh inf -2.3 -> inf -0.0 +asinh1020 asinh inf -inf -> inf -0.78539816339744828 +asinh1021 asinh nan -0.0 -> nan -0.0 +asinh1022 asinh nan -2.3 -> nan nan +asinh1023 asinh nan -inf -> inf nan ignore-real-sign +asinh1024 asinh -0.0 -inf -> -inf -1.5707963267948966 +asinh1025 asinh -2.3 -inf -> -inf -1.5707963267948966 +asinh1026 asinh -0.0 nan -> nan nan +asinh1027 asinh -2.3 nan -> nan nan +asinh1028 asinh -inf -0.0 -> -inf -0.0 +asinh1029 asinh -inf -2.3 -> -inf -0.0 +asinh1030 asinh -inf -inf -> -inf -0.78539816339744828 +asinh1031 asinh -inf nan -> -inf nan +asinh1032 asinh -0.0 inf -> -inf 1.5707963267948966 +asinh1033 asinh -2.3 inf -> -inf 1.5707963267948966 +asinh1034 asinh -inf 0.0 -> -inf 0.0 +asinh1035 asinh -inf 2.3 -> -inf 0.0 +asinh1036 asinh -inf inf -> -inf 0.78539816339744828 + + +--------------------------- +-- atan: Inverse tangent -- +--------------------------- + +-- zeros +atan0000 atan 0.0 0.0 -> 0.0 0.0 +atan0001 atan 0.0 -0.0 -> 0.0 -0.0 +atan0002 atan -0.0 0.0 -> -0.0 0.0 +atan0003 atan -0.0 -0.0 -> -0.0 -0.0 + +-- values along both sides of imaginary axis +atan0010 atan 0.0 -9.8813129168249309e-324 -> 0.0 -9.8813129168249309e-324 +atan0011 atan -0.0 -9.8813129168249309e-324 -> -0.0 -9.8813129168249309e-324 +atan0012 atan 0.0 -1e-305 -> 0.0 -1e-305 +atan0013 atan -0.0 -1e-305 -> -0.0 -1e-305 +atan0014 atan 0.0 -1e-150 -> 0.0 -1e-150 +atan0015 atan -0.0 -1e-150 -> -0.0 -1e-150 +atan0016 atan 0.0 -9.9999999999999998e-17 -> 0.0 -9.9999999999999998e-17 +atan0017 atan -0.0 -9.9999999999999998e-17 -> -0.0 -9.9999999999999998e-17 +atan0018 atan 0.0 -0.001 -> 0.0 -0.0010000003333335333 +atan0019 atan -0.0 -0.001 -> -0.0 -0.0010000003333335333 +atan0020 atan 0.0 -0.57899999999999996 -> 0.0 -0.6609570902866303 +atan0021 atan -0.0 -0.57899999999999996 -> -0.0 -0.6609570902866303 +atan0022 atan 0.0 -0.99999999999999989 -> 0.0 -18.714973875118524 +atan0023 atan -0.0 -0.99999999999999989 -> -0.0 -18.714973875118524 +atan0024 atan 0.0 -1.0000000000000002 -> 1.5707963267948966 -18.36840028483855 +atan0025 atan -0.0 -1.0000000000000002 -> -1.5707963267948966 -18.36840028483855 +atan0026 atan 0.0 -1.0009999999999999 -> 1.5707963267948966 -3.8007011672919218 +atan0027 atan -0.0 -1.0009999999999999 -> -1.5707963267948966 -3.8007011672919218 +atan0028 atan 0.0 -2.0 -> 1.5707963267948966 -0.54930614433405489 +atan0029 atan -0.0 -2.0 -> -1.5707963267948966 -0.54930614433405489 +atan0030 atan 0.0 -20.0 -> 1.5707963267948966 -0.050041729278491265 +atan0031 atan -0.0 -20.0 -> -1.5707963267948966 -0.050041729278491265 +atan0032 atan 0.0 -10000000000000000.0 -> 1.5707963267948966 -9.9999999999999998e-17 +atan0033 atan -0.0 -10000000000000000.0 -> -1.5707963267948966 -9.9999999999999998e-17 +atan0034 atan 0.0 -9.9999999999999998e+149 -> 1.5707963267948966 -1e-150 +atan0035 atan -0.0 -9.9999999999999998e+149 -> -1.5707963267948966 -1e-150 +atan0036 atan 0.0 -1.0000000000000001e+299 -> 1.5707963267948966 -9.9999999999999999e-300 +atan0037 atan -0.0 -1.0000000000000001e+299 -> -1.5707963267948966 -9.9999999999999999e-300 +atan0038 atan 0.0 9.8813129168249309e-324 -> 0.0 9.8813129168249309e-324 +atan0039 atan -0.0 9.8813129168249309e-324 -> -0.0 9.8813129168249309e-324 +atan0040 atan 0.0 1e-305 -> 0.0 1e-305 +atan0041 atan -0.0 1e-305 -> -0.0 1e-305 +atan0042 atan 0.0 1e-150 -> 0.0 1e-150 +atan0043 atan -0.0 1e-150 -> -0.0 1e-150 +atan0044 atan 0.0 9.9999999999999998e-17 -> 0.0 9.9999999999999998e-17 +atan0045 atan -0.0 9.9999999999999998e-17 -> -0.0 9.9999999999999998e-17 +atan0046 atan 0.0 0.001 -> 0.0 0.0010000003333335333 +atan0047 atan -0.0 0.001 -> -0.0 0.0010000003333335333 +atan0048 atan 0.0 0.57899999999999996 -> 0.0 0.6609570902866303 +atan0049 atan -0.0 0.57899999999999996 -> -0.0 0.6609570902866303 +atan0050 atan 0.0 0.99999999999999989 -> 0.0 18.714973875118524 +atan0051 atan -0.0 0.99999999999999989 -> -0.0 18.714973875118524 +atan0052 atan 0.0 1.0000000000000002 -> 1.5707963267948966 18.36840028483855 +atan0053 atan -0.0 1.0000000000000002 -> -1.5707963267948966 18.36840028483855 +atan0054 atan 0.0 1.0009999999999999 -> 1.5707963267948966 3.8007011672919218 +atan0055 atan -0.0 1.0009999999999999 -> -1.5707963267948966 3.8007011672919218 +atan0056 atan 0.0 2.0 -> 1.5707963267948966 0.54930614433405489 +atan0057 atan -0.0 2.0 -> -1.5707963267948966 0.54930614433405489 +atan0058 atan 0.0 20.0 -> 1.5707963267948966 0.050041729278491265 +atan0059 atan -0.0 20.0 -> -1.5707963267948966 0.050041729278491265 +atan0060 atan 0.0 10000000000000000.0 -> 1.5707963267948966 9.9999999999999998e-17 +atan0061 atan -0.0 10000000000000000.0 -> -1.5707963267948966 9.9999999999999998e-17 +atan0062 atan 0.0 9.9999999999999998e+149 -> 1.5707963267948966 1e-150 +atan0063 atan -0.0 9.9999999999999998e+149 -> -1.5707963267948966 1e-150 +atan0064 atan 0.0 1.0000000000000001e+299 -> 1.5707963267948966 9.9999999999999999e-300 +atan0065 atan -0.0 1.0000000000000001e+299 -> -1.5707963267948966 9.9999999999999999e-300 + +-- random inputs +atan0100 atan -0.32538873661060214 -1.5530461550412578 -> -1.3682728427554227 -0.69451401598762041 +atan0101 atan -0.45863393495197929 -4799.1747094903594 -> -1.5707963068820623 -0.00020836916050636145 +atan0102 atan -8.3006999685976162 -2.6788890251790938 -> -1.4619862771810199 -0.034811669653327826 +atan0103 atan -1.8836307682985314 -1.1441976638861771 -> -1.1839984370871612 -0.20630956157312796 +atan0104 atan -0.00063230482407491669 -4.9312520961829485 -> -1.5707692093223147 -0.20563867743008304 +atan0105 atan -0.84278137150065946 179012.37493146997 -> -1.5707963267685969 5.5862059836425272e-06 +atan0106 atan -0.95487853984049287 14.311334539886177 -> -1.5661322859434561 0.069676024526232005 +atan0107 atan -1.3513252539663239 6.0500727021632198e-08 -> -0.93371676315220975 2.140800269742656e-08 +atan0108 atan -0.20566254458595795 0.11933771944159823 -> -0.20556463711174916 0.11493405387141732 +atan0109 atan -0.58563718795408559 0.64438965423212868 -> -0.68361089300233124 0.46759762751800249 +atan0110 atan 48.479267751948292 -78.386382460112543 -> 1.5650888770910523 -0.0092276811373297584 +atan0111 atan 1.0575373914056061 -0.75988012377296987 -> 0.94430886722043594 -0.31915698126703118 +atan0112 atan 4444810.4314677203 -0.56553404593942558 -> 1.5707961018134231 -2.8625446437701909e-14 +atan0113 atan 0.010101405082520009 -0.032932668550282478 -> 0.01011202676646334 -0.032941214776834996 +atan0114 atan 1.5353585300154911 -2.1947099346796519 -> 1.3400310739206394 -0.29996003607449045 +atan0115 atan 0.21869457055670882 9.9915684254007093 -> 1.5685846078876444 0.1003716881759439 +atan0116 atan 0.17783290150246836 0.064334689863650957 -> 0.17668728064286277 0.062435808728873846 +atan0117 atan 15.757474087615918 383.57262142534 -> 1.5706894060369621 0.0026026817278826603 +atan0118 atan 10.587017408533317 0.21720238081843438 -> 1.4766594681336236 0.0019199097383010061 +atan0119 atan 0.86026078678781204 0.1230148609359502 -> 0.7147259322534929 0.070551221954286605 + +-- values near infinity +atan0200 atan 7.8764397011195798e+307 8.1647921137746308e+307 -> 1.5707963267948966 6.3439446939604493e-309 +atan0201 atan 1.5873698696131487e+308 -1.0780367422960641e+308 -> 1.5707963267948966 -2.9279309368530781e-309 +atan0202 atan -1.5844551864825834e+308 1.0290657809098675e+308 -> -1.5707963267948966 2.8829614736961417e-309 +atan0203 atan -1.3168792562524032e+308 -9.088432341614825e+307 -> -1.5707963267948966 -3.5499373057390056e-309 +atan0204 atan 0.0 1.0360465742258337e+308 -> 1.5707963267948966 9.6520757355646018e-309 +atan0205 atan -0.0 1.0045063210373196e+308 -> -1.5707963267948966 9.955138947929503e-309 +atan0206 atan 0.0 -9.5155296715763696e+307 -> 1.5707963267948966 -1.050913648020118e-308 +atan0207 atan -0.0 -1.5565700490496501e+308 -> -1.5707963267948966 -6.4243816114189071e-309 +atan0208 atan 1.2956339389525244e+308 0.0 -> 1.5707963267948966 0.0 +atan0209 atan 1.4408126243772151e+308 -0.0 -> 1.5707963267948966 -0.0 +atan0210 atan -1.0631786461936417e+308 0.0 -> -1.5707963267948966 0.0 +atan0211 atan -1.0516056964171069e+308 -0.0 -> -1.5707963267948966 -0.0 +atan0212 atan 1.236162319603838e+308 4.6827953496242936 -> 1.5707963267948966 0.0 +atan0213 atan 7.000516472897218e+307 -5.8631608017844163 -> 1.5707963267948966 -0.0 +atan0214 atan -1.5053444003338508e+308 5.1199197268420313 -> -1.5707963267948966 0.0 +atan0215 atan -1.399172518147259e+308 -3.5687766472913673 -> -1.5707963267948966 -0.0 +atan0216 atan 8.1252833070803021 6.2782953917343822e+307 -> 1.5707963267948966 1.5927890256908564e-308 +atan0217 atan 2.8034285947515167 -1.3378049775753878e+308 -> 1.5707963267948966 -7.4749310756219562e-309 +atan0218 atan -1.4073509988974953 1.6776381785968355e+308 -> -1.5707963267948966 5.9607608646364569e-309 +atan0219 atan -2.7135551527592119 -1.281567445525738e+308 -> -1.5707963267948966 -7.8029447727565326e-309 + +-- imaginary part = +/-1, real part tiny +atan0300 atan -1e-150 -1.0 -> -0.78539816339744828 -173.04045556483339 +atan0301 atan 1e-155 1.0 -> 0.78539816339744828 178.79691829731851 +atan0302 atan 9.9999999999999999e-161 -1.0 -> 0.78539816339744828 -184.55338102980363 +atan0303 atan -1e-165 1.0 -> -0.78539816339744828 190.30984376228875 +atan0304 atan -9.9998886718268301e-321 -1.0 -> -0.78539816339744828 -368.76019403576692 + +-- Additional real values (Jython) +atan0400 atan 1.7976931348623157e+308 0.0 -> 1.5707963267948966192 0.0 +atan0401 atan -1.7976931348623157e+308 0.0 -> -1.5707963267948966192 0.0 +atan0402 atan 1e-17 0.0 -> 1.0000000000000000715e-17 0.0 +atan0403 atan -1e-17 0.0 -> -1.0000000000000000715e-17 0.0 +atan0404 atan 0.0001 0.0 -> 0.000099999999666666673459 0.0 +atan0405 atan -0.0001 0.0 -> -0.000099999999666666673459 0.0 +atan0406 atan 0.999999999999999 0.0 -> 0.78539816339744781002 0.0 +atan0407 atan 1.000000000000001 0.0 -> 0.78539816339744886473 0.0 +atan0408 atan 14.101419947171719 0.0 -> 1.4999999999999999969 0.0 +atan0409 atan 1255.7655915007897 0.0 -> 1.5700000000000000622 0.0 + +-- special values +atan1000 atan -0.0 0.0 -> -0.0 0.0 +atan1001 atan nan 0.0 -> nan 0.0 +atan1002 atan -0.0 1.0 -> -0.0 inf divide-by-zero +atan1003 atan -inf 0.0 -> -1.5707963267948966 0.0 +atan1004 atan -inf 2.2999999999999998 -> -1.5707963267948966 0.0 +atan1005 atan nan 2.2999999999999998 -> nan nan +atan1006 atan -0.0 inf -> -1.5707963267948966 0.0 +atan1007 atan -2.2999999999999998 inf -> -1.5707963267948966 0.0 +atan1008 atan -inf inf -> -1.5707963267948966 0.0 +atan1009 atan nan inf -> nan 0.0 +atan1010 atan -0.0 nan -> nan nan +atan1011 atan -2.2999999999999998 nan -> nan nan +atan1012 atan -inf nan -> -1.5707963267948966 0.0 ignore-imag-sign +atan1013 atan nan nan -> nan nan +atan1014 atan 0.0 0.0 -> 0.0 0.0 +atan1015 atan 0.0 1.0 -> 0.0 inf divide-by-zero +atan1016 atan inf 0.0 -> 1.5707963267948966 0.0 +atan1017 atan inf 2.2999999999999998 -> 1.5707963267948966 0.0 +atan1018 atan 0.0 inf -> 1.5707963267948966 0.0 +atan1019 atan 2.2999999999999998 inf -> 1.5707963267948966 0.0 +atan1020 atan inf inf -> 1.5707963267948966 0.0 +atan1021 atan 0.0 nan -> nan nan +atan1022 atan 2.2999999999999998 nan -> nan nan +atan1023 atan inf nan -> 1.5707963267948966 0.0 ignore-imag-sign +atan1024 atan 0.0 -0.0 -> 0.0 -0.0 +atan1025 atan nan -0.0 -> nan -0.0 +atan1026 atan 0.0 -1.0 -> 0.0 -inf divide-by-zero +atan1027 atan inf -0.0 -> 1.5707963267948966 -0.0 +atan1028 atan inf -2.2999999999999998 -> 1.5707963267948966 -0.0 +atan1029 atan nan -2.2999999999999998 -> nan nan +atan1030 atan 0.0 -inf -> 1.5707963267948966 -0.0 +atan1031 atan 2.2999999999999998 -inf -> 1.5707963267948966 -0.0 +atan1032 atan inf -inf -> 1.5707963267948966 -0.0 +atan1033 atan nan -inf -> nan -0.0 +atan1034 atan -0.0 -0.0 -> -0.0 -0.0 +atan1035 atan -0.0 -1.0 -> -0.0 -inf divide-by-zero +atan1036 atan -inf -0.0 -> -1.5707963267948966 -0.0 +atan1037 atan -inf -2.2999999999999998 -> -1.5707963267948966 -0.0 +atan1038 atan -0.0 -inf -> -1.5707963267948966 -0.0 +atan1039 atan -2.2999999999999998 -inf -> -1.5707963267948966 -0.0 +atan1040 atan -inf -inf -> -1.5707963267948966 -0.0 + + +--------------------------------------- +-- atanh: Inverse hyperbolic tangent -- +--------------------------------------- + +-- zeros +atanh0000 atanh 0.0 0.0 -> 0.0 0.0 +atanh0001 atanh 0.0 -0.0 -> 0.0 -0.0 +atanh0002 atanh -0.0 0.0 -> -0.0 0.0 +atanh0003 atanh -0.0 -0.0 -> -0.0 -0.0 + +-- values along both sides of real axis +atanh0010 atanh -9.8813129168249309e-324 0.0 -> -9.8813129168249309e-324 0.0 +atanh0011 atanh -9.8813129168249309e-324 -0.0 -> -9.8813129168249309e-324 -0.0 +atanh0012 atanh -1e-305 0.0 -> -1e-305 0.0 +atanh0013 atanh -1e-305 -0.0 -> -1e-305 -0.0 +atanh0014 atanh -1e-150 0.0 -> -1e-150 0.0 +atanh0015 atanh -1e-150 -0.0 -> -1e-150 -0.0 +atanh0016 atanh -9.9999999999999998e-17 0.0 -> -9.9999999999999998e-17 0.0 +atanh0017 atanh -9.9999999999999998e-17 -0.0 -> -9.9999999999999998e-17 -0.0 +atanh0018 atanh -0.001 0.0 -> -0.0010000003333335333 0.0 +atanh0019 atanh -0.001 -0.0 -> -0.0010000003333335333 -0.0 +atanh0020 atanh -0.57899999999999996 0.0 -> -0.6609570902866303 0.0 +atanh0021 atanh -0.57899999999999996 -0.0 -> -0.6609570902866303 -0.0 +atanh0022 atanh -0.99999999999999989 0.0 -> -18.714973875118524 0.0 +atanh0023 atanh -0.99999999999999989 -0.0 -> -18.714973875118524 -0.0 +atanh0024 atanh -1.0000000000000002 0.0 -> -18.36840028483855 1.5707963267948966 +atanh0025 atanh -1.0000000000000002 -0.0 -> -18.36840028483855 -1.5707963267948966 +atanh0026 atanh -1.0009999999999999 0.0 -> -3.8007011672919218 1.5707963267948966 +atanh0027 atanh -1.0009999999999999 -0.0 -> -3.8007011672919218 -1.5707963267948966 +atanh0028 atanh -2.0 0.0 -> -0.54930614433405489 1.5707963267948966 +atanh0029 atanh -2.0 -0.0 -> -0.54930614433405489 -1.5707963267948966 +atanh0030 atanh -23.0 0.0 -> -0.043505688494814884 1.5707963267948966 +atanh0031 atanh -23.0 -0.0 -> -0.043505688494814884 -1.5707963267948966 +atanh0032 atanh -10000000000000000.0 0.0 -> -9.9999999999999998e-17 1.5707963267948966 +atanh0033 atanh -10000000000000000.0 -0.0 -> -9.9999999999999998e-17 -1.5707963267948966 +atanh0034 atanh -9.9999999999999998e+149 0.0 -> -1e-150 1.5707963267948966 +atanh0035 atanh -9.9999999999999998e+149 -0.0 -> -1e-150 -1.5707963267948966 +atanh0036 atanh -1.0000000000000001e+299 0.0 -> -9.9999999999999999e-300 1.5707963267948966 +atanh0037 atanh -1.0000000000000001e+299 -0.0 -> -9.9999999999999999e-300 -1.5707963267948966 +atanh0038 atanh 9.8813129168249309e-324 0.0 -> 9.8813129168249309e-324 0.0 +atanh0039 atanh 9.8813129168249309e-324 -0.0 -> 9.8813129168249309e-324 -0.0 +atanh0040 atanh 1e-305 0.0 -> 1e-305 0.0 +atanh0041 atanh 1e-305 -0.0 -> 1e-305 -0.0 +atanh0042 atanh 1e-150 0.0 -> 1e-150 0.0 +atanh0043 atanh 1e-150 -0.0 -> 1e-150 -0.0 +atanh0044 atanh 9.9999999999999998e-17 0.0 -> 9.9999999999999998e-17 0.0 +atanh0045 atanh 9.9999999999999998e-17 -0.0 -> 9.9999999999999998e-17 -0.0 +atanh0046 atanh 0.001 0.0 -> 0.0010000003333335333 0.0 +atanh0047 atanh 0.001 -0.0 -> 0.0010000003333335333 -0.0 +atanh0048 atanh 0.57899999999999996 0.0 -> 0.6609570902866303 0.0 +atanh0049 atanh 0.57899999999999996 -0.0 -> 0.6609570902866303 -0.0 +atanh0050 atanh 0.99999999999999989 0.0 -> 18.714973875118524 0.0 +atanh0051 atanh 0.99999999999999989 -0.0 -> 18.714973875118524 -0.0 +atanh0052 atanh 1.0000000000000002 0.0 -> 18.36840028483855 1.5707963267948966 +atanh0053 atanh 1.0000000000000002 -0.0 -> 18.36840028483855 -1.5707963267948966 +atanh0054 atanh 1.0009999999999999 0.0 -> 3.8007011672919218 1.5707963267948966 +atanh0055 atanh 1.0009999999999999 -0.0 -> 3.8007011672919218 -1.5707963267948966 +atanh0056 atanh 2.0 0.0 -> 0.54930614433405489 1.5707963267948966 +atanh0057 atanh 2.0 -0.0 -> 0.54930614433405489 -1.5707963267948966 +atanh0058 atanh 23.0 0.0 -> 0.043505688494814884 1.5707963267948966 +atanh0059 atanh 23.0 -0.0 -> 0.043505688494814884 -1.5707963267948966 +atanh0060 atanh 10000000000000000.0 0.0 -> 9.9999999999999998e-17 1.5707963267948966 +atanh0061 atanh 10000000000000000.0 -0.0 -> 9.9999999999999998e-17 -1.5707963267948966 +atanh0062 atanh 9.9999999999999998e+149 0.0 -> 1e-150 1.5707963267948966 +atanh0063 atanh 9.9999999999999998e+149 -0.0 -> 1e-150 -1.5707963267948966 +atanh0064 atanh 1.0000000000000001e+299 0.0 -> 9.9999999999999999e-300 1.5707963267948966 +atanh0065 atanh 1.0000000000000001e+299 -0.0 -> 9.9999999999999999e-300 -1.5707963267948966 + +-- random inputs +atanh0100 atanh -0.54460925980633501 -0.54038050126721027 -> -0.41984265808446974 -0.60354153938352828 +atanh0101 atanh -1.6934614269829051 -0.48807386108113621 -> -0.58592769102243281 -1.3537837470975898 +atanh0102 atanh -1.3467293985501207 -0.47868354895395876 -> -0.69961624370709985 -1.1994450156570076 +atanh0103 atanh -5.6142232418984888 -544551613.39307702 -> -1.8932657550925744e-17 -1.5707963249585235 +atanh0104 atanh -0.011841460381263651 -3.259978899823385 -> -0.0010183936547405188 -1.2731614020743838 +atanh0105 atanh -0.0073345736950029532 0.35821949670922248 -> -0.0065004869024682466 0.34399359971920895 +atanh0106 atanh -13.866782244320014 0.9541129545860273 -> -0.071896852055058899 1.5658322704631409 +atanh0107 atanh -708.59964982780775 21.984802159266675 -> -0.0014098779074189741 1.5707525842838959 +atanh0108 atanh -30.916832076030602 1.3691897138829843 -> -0.032292682045743676 1.5693652094847115 +atanh0109 atanh -0.57461806339861754 0.29534797443913063 -> -0.56467464472482765 0.39615612824172625 +atanh0110 atanh 0.40089246737415685 -1.632285984300659 -> 0.1063832707890608 -1.0402821335326482 +atanh0111 atanh 2119.6167688262176 -1.5383653437377242e+17 -> 8.9565008518382049e-32 -1.5707963267948966 +atanh0112 atanh 756.86017850941641 -6.6064087133223817 -> 0.0013211481136820046 -1.5707847948702234 +atanh0113 atanh 4.0490617718041602 -2.5784456791040652e-12 -> 0.25218425538553618 -1.5707963267947291 +atanh0114 atanh 10.589254957173523 -0.13956391149624509 -> 0.094700890282197664 -1.5695407140217623 +atanh0115 atanh 1.0171187553160499 0.70766113465354019 -> 0.55260251975367791 0.96619711116641682 +atanh0116 atanh 0.031645502527750849 0.067319983726544394 -> 0.031513018344086742 0.067285437670549036 +atanh0117 atanh 0.13670177624994517 0.43240089361857947 -> 0.11538933151017253 0.41392008145336212 +atanh0118 atanh 0.64173899243596688 2.9008577686695256 -> 0.065680142424134405 1.2518535724053921 +atanh0119 atanh 0.19313813528025942 38.799619150741869 -> 0.00012820765917366644 1.5450292202823612 + +-- values near infinity +atanh0200 atanh 5.3242646831347954e+307 1.3740396080084153e+308 -> 2.4519253616695576e-309 1.5707963267948966 +atanh0201 atanh 1.158701641241358e+308 -6.5579268873375853e+307 -> 6.5365375267795098e-309 -1.5707963267948966 +atanh0202 atanh -1.3435325735762247e+308 9.8947369259601547e+307 -> -4.8256680906589956e-309 1.5707963267948966 +atanh0203 atanh -1.4359857522598942e+308 -9.4701204702391004e+307 -> -4.8531282262872645e-309 -1.5707963267948966 +atanh0204 atanh 0.0 5.6614181068098497e+307 -> 0.0 1.5707963267948966 +atanh0205 atanh -0.0 6.9813212721450139e+307 -> -0.0 1.5707963267948966 +atanh0206 atanh 0.0 -7.4970613060311453e+307 -> 0.0 -1.5707963267948966 +atanh0207 atanh -0.0 -1.5280601880314068e+308 -> -0.0 -1.5707963267948966 +atanh0208 atanh 8.2219472336000745e+307 0.0 -> 1.2162568933954813e-308 1.5707963267948966 +atanh0209 atanh 1.4811519617280899e+308 -0.0 -> 6.7515017083951325e-309 -1.5707963267948966 +atanh0210 atanh -1.2282016263598785e+308 0.0 -> -8.1419856360537615e-309 1.5707963267948966 +atanh0211 atanh -1.0616427760154426e+308 -0.0 -> -9.4193642399489563e-309 -1.5707963267948966 +atanh0212 atanh 1.2971536510180682e+308 5.2847948452333293 -> 7.7091869510998328e-309 1.5707963267948966 +atanh0213 atanh 1.1849860977411851e+308 -7.9781906447459949 -> 8.4389175696339014e-309 -1.5707963267948966 +atanh0214 atanh -1.4029969422586635e+308 0.93891986543663375 -> -7.127599283218073e-309 1.5707963267948966 +atanh0215 atanh -4.7508098912248211e+307 -8.2702421247039908 -> -2.1049042645278043e-308 -1.5707963267948966 +atanh0216 atanh 8.2680742115769998 8.1153898410918065e+307 -> 0.0 1.5707963267948966 +atanh0217 atanh 1.2575325146218885 -1.4746679147661649e+308 -> 0.0 -1.5707963267948966 +atanh0218 atanh -2.4618803682310899 1.3781522717005568e+308 -> -0.0 1.5707963267948966 +atanh0219 atanh -4.0952386694788112 -1.231083376353703e+308 -> -0.0 -1.5707963267948966 + +-- values near 0 +atanh0220 atanh 3.8017563659811628e-314 2.6635484239074319e-312 -> 3.8017563659811628e-314 2.6635484239074319e-312 +atanh0221 atanh 1.7391110733611878e-321 -4.3547800672541419e-313 -> 1.7391110733611878e-321 -4.3547800672541419e-313 +atanh0222 atanh -5.9656816081325078e-317 9.9692253555416263e-313 -> -5.9656816081325078e-317 9.9692253555416263e-313 +atanh0223 atanh -6.5606671178400239e-313 -2.1680936406357335e-309 -> -6.5606671178400239e-313 -2.1680936406357335e-309 +atanh0224 atanh 0.0 2.5230944401820779e-319 -> 0.0 2.5230944401820779e-319 +atanh0225 atanh -0.0 5.6066569490064658e-320 -> -0.0 5.6066569490064658e-320 +atanh0226 atanh 0.0 -2.4222487249468377e-317 -> 0.0 -2.4222487249468377e-317 +atanh0227 atanh -0.0 -3.0861101089206037e-316 -> -0.0 -3.0861101089206037e-316 +atanh0228 atanh 3.1219222884393986e-310 0.0 -> 3.1219222884393986e-310 0.0 +atanh0229 atanh 9.8926337564976196e-309 -0.0 -> 9.8926337564976196e-309 -0.0 +atanh0230 atanh -1.5462535092918154e-312 0.0 -> -1.5462535092918154e-312 0.0 +atanh0231 atanh -9.8813129168249309e-324 -0.0 -> -9.8813129168249309e-324 -0.0 + +-- real part = +/-1, imaginary part tiny +atanh0300 atanh 1.0 1e-153 -> 176.49433320432448 0.78539816339744828 +atanh0301 atanh 1.0 9.9999999999999997e-155 -> 177.64562575082149 0.78539816339744828 +atanh0302 atanh -1.0 1e-161 -> -185.70467357630065 0.78539816339744828 +atanh0303 atanh 1.0 -1e-165 -> 190.30984376228875 -0.78539816339744828 +atanh0304 atanh -1.0 -9.8813129168249309e-324 -> -372.22003596069061 -0.78539816339744828 + +-- special values +atanh1000 atanh 0.0 0.0 -> 0.0 0.0 +atanh1001 atanh 0.0 nan -> 0.0 nan +atanh1002 atanh 1.0 0.0 -> inf 0.0 divide-by-zero +atanh1003 atanh 0.0 inf -> 0.0 1.5707963267948966 +atanh1004 atanh 2.3 inf -> 0.0 1.5707963267948966 +atanh1005 atanh 2.3 nan -> nan nan +atanh1006 atanh inf 0.0 -> 0.0 1.5707963267948966 +atanh1007 atanh inf 2.3 -> 0.0 1.5707963267948966 +atanh1008 atanh inf inf -> 0.0 1.5707963267948966 +atanh1009 atanh inf nan -> 0.0 nan +atanh1010 atanh nan 0.0 -> nan nan +atanh1011 atanh nan 2.3 -> nan nan +atanh1012 atanh nan inf -> 0.0 1.5707963267948966 ignore-real-sign +atanh1013 atanh nan nan -> nan nan +atanh1014 atanh 0.0 -0.0 -> 0.0 -0.0 +atanh1015 atanh 1.0 -0.0 -> inf -0.0 divide-by-zero +atanh1016 atanh 0.0 -inf -> 0.0 -1.5707963267948966 +atanh1017 atanh 2.3 -inf -> 0.0 -1.5707963267948966 +atanh1018 atanh inf -0.0 -> 0.0 -1.5707963267948966 +atanh1019 atanh inf -2.3 -> 0.0 -1.5707963267948966 +atanh1020 atanh inf -inf -> 0.0 -1.5707963267948966 +atanh1021 atanh nan -0.0 -> nan nan +atanh1022 atanh nan -2.3 -> nan nan +atanh1023 atanh nan -inf -> 0.0 -1.5707963267948966 ignore-real-sign +atanh1024 atanh -0.0 -0.0 -> -0.0 -0.0 +atanh1025 atanh -0.0 nan -> -0.0 nan +atanh1026 atanh -1.0 -0.0 -> -inf -0.0 divide-by-zero +atanh1027 atanh -0.0 -inf -> -0.0 -1.5707963267948966 +atanh1028 atanh -2.3 -inf -> -0.0 -1.5707963267948966 +atanh1029 atanh -2.3 nan -> nan nan +atanh1030 atanh -inf -0.0 -> -0.0 -1.5707963267948966 +atanh1031 atanh -inf -2.3 -> -0.0 -1.5707963267948966 +atanh1032 atanh -inf -inf -> -0.0 -1.5707963267948966 +atanh1033 atanh -inf nan -> -0.0 nan +atanh1034 atanh -0.0 0.0 -> -0.0 0.0 +atanh1035 atanh -1.0 0.0 -> -inf 0.0 divide-by-zero +atanh1036 atanh -0.0 inf -> -0.0 1.5707963267948966 +atanh1037 atanh -2.3 inf -> -0.0 1.5707963267948966 +atanh1038 atanh -inf 0.0 -> -0.0 1.5707963267948966 +atanh1039 atanh -inf 2.3 -> -0.0 1.5707963267948966 +atanh1040 atanh -inf inf -> -0.0 1.5707963267948966 + + +---------------------------- +-- log: Natural logarithm -- +---------------------------- + +log0000 log 1.0 0.0 -> 0.0 0.0 +log0001 log 1.0 -0.0 -> 0.0 -0.0 +log0002 log -1.0 0.0 -> 0.0 3.1415926535897931 +log0003 log -1.0 -0.0 -> 0.0 -3.1415926535897931 +-- values along both sides of real axis +log0010 log -9.8813129168249309e-324 0.0 -> -743.74692474082133 3.1415926535897931 +log0011 log -9.8813129168249309e-324 -0.0 -> -743.74692474082133 -3.1415926535897931 +log0012 log -1e-305 0.0 -> -702.28845336318398 3.1415926535897931 +log0013 log -1e-305 -0.0 -> -702.28845336318398 -3.1415926535897931 +log0014 log -1e-150 0.0 -> -345.38776394910684 3.1415926535897931 +log0015 log -1e-150 -0.0 -> -345.38776394910684 -3.1415926535897931 +log0016 log -9.9999999999999998e-17 0.0 -> -36.841361487904734 3.1415926535897931 +log0017 log -9.9999999999999998e-17 -0.0 -> -36.841361487904734 -3.1415926535897931 +log0018 log -0.001 0.0 -> -6.9077552789821368 3.1415926535897931 +log0019 log -0.001 -0.0 -> -6.9077552789821368 -3.1415926535897931 +log0020 log -0.57899999999999996 0.0 -> -0.54645280140914188 3.1415926535897931 +log0021 log -0.57899999999999996 -0.0 -> -0.54645280140914188 -3.1415926535897931 +log0022 log -0.99999999999999989 0.0 -> -1.1102230246251565e-16 3.1415926535897931 +log0023 log -0.99999999999999989 -0.0 -> -1.1102230246251565e-16 -3.1415926535897931 +log0024 log -1.0000000000000002 0.0 -> 2.2204460492503128e-16 3.1415926535897931 +log0025 log -1.0000000000000002 -0.0 -> 2.2204460492503128e-16 -3.1415926535897931 +log0026 log -1.0009999999999999 0.0 -> 0.00099950033308342321 3.1415926535897931 +log0027 log -1.0009999999999999 -0.0 -> 0.00099950033308342321 -3.1415926535897931 +log0028 log -2.0 0.0 -> 0.69314718055994529 3.1415926535897931 +log0029 log -2.0 -0.0 -> 0.69314718055994529 -3.1415926535897931 +log0030 log -23.0 0.0 -> 3.1354942159291497 3.1415926535897931 +log0031 log -23.0 -0.0 -> 3.1354942159291497 -3.1415926535897931 +log0032 log -10000000000000000.0 0.0 -> 36.841361487904734 3.1415926535897931 +log0033 log -10000000000000000.0 -0.0 -> 36.841361487904734 -3.1415926535897931 +log0034 log -9.9999999999999998e+149 0.0 -> 345.38776394910684 3.1415926535897931 +log0035 log -9.9999999999999998e+149 -0.0 -> 345.38776394910684 -3.1415926535897931 +log0036 log -1.0000000000000001e+299 0.0 -> 688.47294280521965 3.1415926535897931 +log0037 log -1.0000000000000001e+299 -0.0 -> 688.47294280521965 -3.1415926535897931 +log0038 log 9.8813129168249309e-324 0.0 -> -743.74692474082133 0.0 +log0039 log 9.8813129168249309e-324 -0.0 -> -743.74692474082133 -0.0 +log0040 log 1e-305 0.0 -> -702.28845336318398 0.0 +log0041 log 1e-305 -0.0 -> -702.28845336318398 -0.0 +log0042 log 1e-150 0.0 -> -345.38776394910684 0.0 +log0043 log 1e-150 -0.0 -> -345.38776394910684 -0.0 +log0044 log 9.9999999999999998e-17 0.0 -> -36.841361487904734 0.0 +log0045 log 9.9999999999999998e-17 -0.0 -> -36.841361487904734 -0.0 +log0046 log 0.001 0.0 -> -6.9077552789821368 0.0 +log0047 log 0.001 -0.0 -> -6.9077552789821368 -0.0 +log0048 log 0.57899999999999996 0.0 -> -0.54645280140914188 0.0 +log0049 log 0.57899999999999996 -0.0 -> -0.54645280140914188 -0.0 +log0050 log 0.99999999999999989 0.0 -> -1.1102230246251565e-16 0.0 +log0051 log 0.99999999999999989 -0.0 -> -1.1102230246251565e-16 -0.0 +log0052 log 1.0000000000000002 0.0 -> 2.2204460492503128e-16 0.0 +log0053 log 1.0000000000000002 -0.0 -> 2.2204460492503128e-16 -0.0 +log0054 log 1.0009999999999999 0.0 -> 0.00099950033308342321 0.0 +log0055 log 1.0009999999999999 -0.0 -> 0.00099950033308342321 -0.0 +log0056 log 2.0 0.0 -> 0.69314718055994529 0.0 +log0057 log 2.0 -0.0 -> 0.69314718055994529 -0.0 +log0058 log 23.0 0.0 -> 3.1354942159291497 0.0 +log0059 log 23.0 -0.0 -> 3.1354942159291497 -0.0 +log0060 log 10000000000000000.0 0.0 -> 36.841361487904734 0.0 +log0061 log 10000000000000000.0 -0.0 -> 36.841361487904734 -0.0 +log0062 log 9.9999999999999998e+149 0.0 -> 345.38776394910684 0.0 +log0063 log 9.9999999999999998e+149 -0.0 -> 345.38776394910684 -0.0 +log0064 log 1.0000000000000001e+299 0.0 -> 688.47294280521965 0.0 +log0065 log 1.0000000000000001e+299 -0.0 -> 688.47294280521965 -0.0 + +-- random inputs +log0066 log -1.9830454945186191e-16 -2.0334448025673346 -> 0.70973130194329803 -1.5707963267948968 +log0067 log -0.96745853024741857 -0.84995816228299692 -> 0.25292811398722387 -2.4207570438536905 +log0068 log -0.1603644313948418 -0.2929942111041835 -> -1.0965857872427374 -2.0715870859971419 +log0069 log -0.15917913168438699 -0.25238799251132177 -> -1.2093477313249901 -2.1334784232033863 +log0070 log -0.68907818535078802 -3.0693105853476346 -> 1.1460398629184565 -1.7916403813913211 +log0071 log -17.268133447565589 6.8165120014604756 -> 2.9212694465974836 2.7656245081603164 +log0072 log -1.7153894479690328 26.434055372802636 -> 3.2767542953718003 1.6355986276341734 +log0073 log -8.0456794648936578e-06 0.19722758057570208 -> -1.6233969848296075 1.5708371206810101 +log0074 log -2.4306442691323173 0.6846919750700996 -> 0.92633592001969589 2.8670160576718331 +log0075 log -3.5488049250888194 0.45324040643185254 -> 1.2747008374256426 3.0145640007885111 +log0076 log 0.18418516851510189 -0.26062518836212617 -> -1.1421287121940344 -0.95558440841183434 +log0077 log 2.7124837795638399 -13.148769067133387 -> 2.5971659975706802 -1.3673583045209439 +log0078 log 3.6521275476169149e-13 -3.7820543023170673e-05 -> -10.182658136741569 -1.5707963171384316 +log0079 log 5.0877545813862239 -1.2834978326786852 -> 1.6576856213076328 -0.24711583497738485 +log0080 log 0.26477986808461512 -0.67659001194187429 -> -0.31944085207999973 -1.197773671987121 +log0081 log 0.0014754261398071962 5.3514691608205442 -> 1.6773711707153829 1.5705206219261802 +log0082 log 0.29667334462157885 0.00020056045042584795 -> -1.2151233667079588 0.00067603114168689204 +log0083 log 0.82104233671099425 3.9005387130133102 -> 1.3827918965299593 1.3633304701848363 +log0084 log 0.27268135358180667 124.42088110945804 -> 4.8236724223559229 1.5686047258789015 +log0085 log 0.0026286959168267485 0.47795808180573013 -> -0.73821712137809126 1.5652965360960087 + +-- values near infinity +log0100 log 1.0512025744003172e+308 7.2621669750664611e+307 -> 709.44123967814494 0.60455434048332968 +log0101 log 5.5344249034372126e+307 -1.2155859158431275e+308 -> 709.48562300345679 -1.143553056717973 +log0102 log -1.3155575403469408e+308 1.1610793541663864e+308 -> 709.75847809546428 2.41848796504974 +log0103 log -1.632366720973235e+308 -1.54299446211448e+308 -> 710.00545236515586 -2.3843326028455087 +log0104 log 0.0 5.9449276692327712e+307 -> 708.67616191258526 1.5707963267948966 +log0105 log -0.0 1.1201850459025692e+308 -> 709.30970253338171 1.5707963267948966 +log0106 log 0.0 -1.6214225933466528e+308 -> 709.6795125501086 -1.5707963267948966 +log0107 log -0.0 -1.7453269791591058e+308 -> 709.75315056087379 -1.5707963267948966 +log0108 log 1.440860577601428e+308 0.0 -> 709.56144920058262 0.0 +log0109 log 1.391515176148282e+308 -0.0 -> 709.52660185041327 -0.0 +log0110 log -1.201354401295296e+308 0.0 -> 709.37965823023956 3.1415926535897931 +log0111 log -1.6704337825976804e+308 -0.0 -> 709.70929198492399 -3.1415926535897931 +log0112 log 7.2276974655190223e+307 7.94879711369164 -> 708.87154406512104 1.0997689307850458e-307 +log0113 log 1.1207859593716076e+308 -6.1956200868221147 -> 709.31023883080104 -5.5279244310803286e-308 +log0114 log -4.6678933874471045e+307 9.947107893220382 -> 708.43433142431388 3.1415926535897931 +log0115 log -1.5108012453950142e+308 -5.3117197179375619 -> 709.60884877835008 -3.1415926535897931 +log0116 log 7.4903750871504435 1.5320703776626352e+308 -> 709.62282865085137 1.5707963267948966 +log0117 log 5.9760325525654778 -8.0149473997349123e+307 -> 708.97493177248396 -1.5707963267948966 +log0118 log -7.880194206386629 1.7861845814767441e+308 -> 709.77629046837137 1.5707963267948966 +log0119 log -9.886438993852865 -6.19235781080747e+307 -> 708.71693946977302 -1.5707963267948966 + +-- values near 0 +log0120 log 2.2996867579227779e-308 6.7861840770939125e-312 -> -708.36343567717392 0.00029509166223339815 +log0121 log 6.9169190417774516e-323 -9.0414013188948118e-322 -> -739.22766796468386 -1.4944423210001669 +log0122 log -1.5378064962914011e-316 1.8243628389354635e-310 -> -713.20014803142965 1.5707971697228842 +log0123 log -2.3319898483706837e-321 -2.2358763941866371e-313 -> -719.9045008332522 -1.570796337224766 +log0124 log 0.0 3.872770101081121e-315 -> -723.96033425374401 1.5707963267948966 +log0125 log -0.0 9.6342800939043076e-322 -> -739.16707236281752 1.5707963267948966 +log0126 log 0.0 -2.266099393427834e-308 -> -708.37814861757965 -1.5707963267948966 +log0127 log -0.0 -2.1184695673766626e-315 -> -724.56361036731812 -1.5707963267948966 +log0128 log 1.1363509854348671e-322 0.0 -> -741.30457770545206 0.0 +log0129 log 3.5572726500569751e-322 -0.0 -> -740.16340580236522 -0.0 +log0130 log -2.3696071074040593e-310 0.0 -> -712.93865466421641 3.1415926535897931 +log0131 log -2.813283897266934e-317 -0.0 -> -728.88512203138862 -3.1415926535897931 + +-- values near the unit circle +log0200 log -0.59999999999999998 0.80000000000000004 -> 2.2204460492503132e-17 2.2142974355881808 +log0201 log 0.79999999999999993 0.60000000000000009 -> 6.1629758220391547e-33 0.64350110879328448 + +-- special values +log1000 log -0.0 0.0 -> -inf 3.1415926535897931 divide-by-zero +log1001 log 0.0 0.0 -> -inf 0.0 divide-by-zero +log1002 log 0.0 inf -> inf 1.5707963267948966 +log1003 log 2.3 inf -> inf 1.5707963267948966 +log1004 log -0.0 inf -> inf 1.5707963267948966 +log1005 log -2.3 inf -> inf 1.5707963267948966 +log1006 log 0.0 nan -> nan nan +log1007 log 2.3 nan -> nan nan +log1008 log -0.0 nan -> nan nan +log1009 log -2.3 nan -> nan nan +log1010 log -inf 0.0 -> inf 3.1415926535897931 +log1011 log -inf 2.3 -> inf 3.1415926535897931 +log1012 log inf 0.0 -> inf 0.0 +log1013 log inf 2.3 -> inf 0.0 +log1014 log -inf inf -> inf 2.3561944901923448 +log1015 log inf inf -> inf 0.78539816339744828 +log1016 log inf nan -> inf nan +log1017 log -inf nan -> inf nan +log1018 log nan 0.0 -> nan nan +log1019 log nan 2.3 -> nan nan +log1020 log nan inf -> inf nan +log1021 log nan nan -> nan nan +log1022 log -0.0 -0.0 -> -inf -3.1415926535897931 divide-by-zero +log1023 log 0.0 -0.0 -> -inf -0.0 divide-by-zero +log1024 log 0.0 -inf -> inf -1.5707963267948966 +log1025 log 2.3 -inf -> inf -1.5707963267948966 +log1026 log -0.0 -inf -> inf -1.5707963267948966 +log1027 log -2.3 -inf -> inf -1.5707963267948966 +log1028 log -inf -0.0 -> inf -3.1415926535897931 +log1029 log -inf -2.3 -> inf -3.1415926535897931 +log1030 log inf -0.0 -> inf -0.0 +log1031 log inf -2.3 -> inf -0.0 +log1032 log -inf -inf -> inf -2.3561944901923448 +log1033 log inf -inf -> inf -0.78539816339744828 +log1034 log nan -0.0 -> nan nan +log1035 log nan -2.3 -> nan nan +log1036 log nan -inf -> inf nan + + +------------------------------ +-- log10: Logarithm base 10 -- +------------------------------ + +logt0000 log10 1.0 0.0 -> 0.0 0.0 +logt0001 log10 1.0 -0.0 -> 0.0 -0.0 +logt0002 log10 -1.0 0.0 -> 0.0 1.3643763538418414 +logt0003 log10 -1.0 -0.0 -> 0.0 -1.3643763538418414 +-- values along both sides of real axis +logt0010 log10 -9.8813129168249309e-324 0.0 -> -323.0051853474518 1.3643763538418414 +logt0011 log10 -9.8813129168249309e-324 -0.0 -> -323.0051853474518 -1.3643763538418414 +logt0012 log10 -1e-305 0.0 -> -305.0 1.3643763538418414 +logt0013 log10 -1e-305 -0.0 -> -305.0 -1.3643763538418414 +logt0014 log10 -1e-150 0.0 -> -150.0 1.3643763538418414 +logt0015 log10 -1e-150 -0.0 -> -150.0 -1.3643763538418414 +logt0016 log10 -9.9999999999999998e-17 0.0 -> -16.0 1.3643763538418414 +logt0017 log10 -9.9999999999999998e-17 -0.0 -> -16.0 -1.3643763538418414 +logt0018 log10 -0.001 0.0 -> -3.0 1.3643763538418414 +logt0019 log10 -0.001 -0.0 -> -3.0 -1.3643763538418414 +logt0020 log10 -0.57899999999999996 0.0 -> -0.23732143627256383 1.3643763538418414 +logt0021 log10 -0.57899999999999996 -0.0 -> -0.23732143627256383 -1.3643763538418414 +logt0022 log10 -0.99999999999999989 0.0 -> -4.821637332766436e-17 1.3643763538418414 +logt0023 log10 -0.99999999999999989 -0.0 -> -4.821637332766436e-17 -1.3643763538418414 +logt0024 log10 -1.0000000000000002 0.0 -> 9.6432746655328696e-17 1.3643763538418414 +logt0025 log10 -1.0000000000000002 -0.0 -> 9.6432746655328696e-17 -1.3643763538418414 +logt0026 log10 -1.0009999999999999 0.0 -> 0.0004340774793185929 1.3643763538418414 +logt0027 log10 -1.0009999999999999 -0.0 -> 0.0004340774793185929 -1.3643763538418414 +logt0028 log10 -2.0 0.0 -> 0.3010299956639812 1.3643763538418414 +logt0029 log10 -2.0 -0.0 -> 0.3010299956639812 -1.3643763538418414 +logt0030 log10 -23.0 0.0 -> 1.3617278360175928 1.3643763538418414 +logt0031 log10 -23.0 -0.0 -> 1.3617278360175928 -1.3643763538418414 +logt0032 log10 -10000000000000000.0 0.0 -> 16.0 1.3643763538418414 +logt0033 log10 -10000000000000000.0 -0.0 -> 16.0 -1.3643763538418414 +logt0034 log10 -9.9999999999999998e+149 0.0 -> 150.0 1.3643763538418414 +logt0035 log10 -9.9999999999999998e+149 -0.0 -> 150.0 -1.3643763538418414 +logt0036 log10 -1.0000000000000001e+299 0.0 -> 299.0 1.3643763538418414 +logt0037 log10 -1.0000000000000001e+299 -0.0 -> 299.0 -1.3643763538418414 +logt0038 log10 9.8813129168249309e-324 0.0 -> -323.0051853474518 0.0 +logt0039 log10 9.8813129168249309e-324 -0.0 -> -323.0051853474518 -0.0 +logt0040 log10 1e-305 0.0 -> -305.0 0.0 +logt0041 log10 1e-305 -0.0 -> -305.0 -0.0 +logt0042 log10 1e-150 0.0 -> -150.0 0.0 +logt0043 log10 1e-150 -0.0 -> -150.0 -0.0 +logt0044 log10 9.9999999999999998e-17 0.0 -> -16.0 0.0 +logt0045 log10 9.9999999999999998e-17 -0.0 -> -16.0 -0.0 +logt0046 log10 0.001 0.0 -> -3.0 0.0 +logt0047 log10 0.001 -0.0 -> -3.0 -0.0 +logt0048 log10 0.57899999999999996 0.0 -> -0.23732143627256383 0.0 +logt0049 log10 0.57899999999999996 -0.0 -> -0.23732143627256383 -0.0 +logt0050 log10 0.99999999999999989 0.0 -> -4.821637332766436e-17 0.0 +logt0051 log10 0.99999999999999989 -0.0 -> -4.821637332766436e-17 -0.0 +logt0052 log10 1.0000000000000002 0.0 -> 9.6432746655328696e-17 0.0 +logt0053 log10 1.0000000000000002 -0.0 -> 9.6432746655328696e-17 -0.0 +logt0054 log10 1.0009999999999999 0.0 -> 0.0004340774793185929 0.0 +logt0055 log10 1.0009999999999999 -0.0 -> 0.0004340774793185929 -0.0 +logt0056 log10 2.0 0.0 -> 0.3010299956639812 0.0 +logt0057 log10 2.0 -0.0 -> 0.3010299956639812 -0.0 +logt0058 log10 23.0 0.0 -> 1.3617278360175928 0.0 +logt0059 log10 23.0 -0.0 -> 1.3617278360175928 -0.0 +logt0060 log10 10000000000000000.0 0.0 -> 16.0 0.0 +logt0061 log10 10000000000000000.0 -0.0 -> 16.0 -0.0 +logt0062 log10 9.9999999999999998e+149 0.0 -> 150.0 0.0 +logt0063 log10 9.9999999999999998e+149 -0.0 -> 150.0 -0.0 +logt0064 log10 1.0000000000000001e+299 0.0 -> 299.0 0.0 +logt0065 log10 1.0000000000000001e+299 -0.0 -> 299.0 -0.0 + +-- random inputs +logt0066 log10 -1.9830454945186191e-16 -2.0334448025673346 -> 0.30823238806798503 -0.68218817692092071 +logt0067 log10 -0.96745853024741857 -0.84995816228299692 -> 0.10984528422284802 -1.051321426174086 +logt0068 log10 -0.1603644313948418 -0.2929942111041835 -> -0.47624115633305419 -0.89967884023059597 +logt0069 log10 -0.15917913168438699 -0.25238799251132177 -> -0.52521304641665956 -0.92655790645688119 +logt0070 log10 -0.68907818535078802 -3.0693105853476346 -> 0.4977187885066448 -0.77809953119328823 +logt0071 log10 -17.268133447565589 6.8165120014604756 -> 1.2686912008098534 1.2010954629104202 +logt0072 log10 -1.7153894479690328 26.434055372802636 -> 1.423076309032751 0.71033145859005309 +logt0073 log10 -8.0456794648936578e-06 0.19722758057570208 -> -0.70503235244987561 0.68220589348055516 +logt0074 log10 -2.4306442691323173 0.6846919750700996 -> 0.40230257845332595 1.2451292533748923 +logt0075 log10 -3.5488049250888194 0.45324040643185254 -> 0.55359553977141063 1.3092085108866405 +logt0076 log10 0.18418516851510189 -0.26062518836212617 -> -0.49602019732913638 -0.41500503556604301 +logt0077 log10 2.7124837795638399 -13.148769067133387 -> 1.1279348613317008 -0.59383616643803216 +logt0078 log10 3.6521275476169149e-13 -3.7820543023170673e-05 -> -4.4222722398941112 -0.68218817272717114 +logt0079 log10 5.0877545813862239 -1.2834978326786852 -> 0.71992371806426847 -0.10732104352159283 +logt0080 log10 0.26477986808461512 -0.67659001194187429 -> -0.13873139935281681 -0.52018649631300229 +logt0081 log10 0.0014754261398071962 5.3514691608205442 -> 0.72847304354528819 0.6820684398178033 +logt0082 log10 0.29667334462157885 0.00020056045042584795 -> -0.52772137299296806 0.00029359659442937261 +logt0083 log10 0.82104233671099425 3.9005387130133102 -> 0.60053889028349361 0.59208690021184018 +logt0084 log10 0.27268135358180667 124.42088110945804 -> 2.094894315538069 0.68123637673656989 +logt0085 log10 0.0026286959168267485 0.47795808180573013 -> -0.32060362226100814 0.67979964816877081 + +-- values near infinity +logt0100 log10 1.0512025744003172e+308 7.2621669750664611e+307 -> 308.10641562682065 0.26255461408256975 +logt0101 log10 5.5344249034372126e+307 -1.2155859158431275e+308 -> 308.12569106009209 -0.496638782296212 +logt0102 log10 -1.3155575403469408e+308 1.1610793541663864e+308 -> 308.24419052091019 1.0503359777705266 +logt0103 log10 -1.632366720973235e+308 -1.54299446211448e+308 -> 308.3514500834093 -1.0355024924378222 +logt0104 log10 0.0 5.9449276692327712e+307 -> 307.77414657501117 0.68218817692092071 +logt0105 log10 -0.0 1.1201850459025692e+308 -> 308.04928977068465 0.68218817692092071 +logt0106 log10 0.0 -1.6214225933466528e+308 -> 308.20989622030174 -0.68218817692092071 +logt0107 log10 -0.0 -1.7453269791591058e+308 -> 308.24187680203539 -0.68218817692092071 +logt0108 log10 1.440860577601428e+308 0.0 -> 308.15862195908755 0.0 +logt0109 log10 1.391515176148282e+308 -0.0 -> 308.14348794720007 -0.0 +logt0110 log10 -1.201354401295296e+308 0.0 -> 308.07967114380773 1.3643763538418414 +logt0111 log10 -1.6704337825976804e+308 -0.0 -> 308.22282926451624 -1.3643763538418414 +logt0112 log10 7.2276974655190223e+307 7.94879711369164 -> 307.85899996571993 4.7762357800858463e-308 +logt0113 log10 1.1207859593716076e+308 -6.1956200868221147 -> 308.04952268169455 -2.4007470767963597e-308 +logt0114 log10 -4.6678933874471045e+307 9.947107893220382 -> 307.66912092839902 1.3643763538418414 +logt0115 log10 -1.5108012453950142e+308 -5.3117197179375619 -> 308.1792073341565 -1.3643763538418414 +logt0116 log10 7.4903750871504435 1.5320703776626352e+308 -> 308.18527871564157 0.68218817692092071 +logt0117 log10 5.9760325525654778 -8.0149473997349123e+307 -> 307.90390067652424 -0.68218817692092071 +logt0118 log10 -7.880194206386629 1.7861845814767441e+308 -> 308.25192633617331 0.68218817692092071 +logt0119 log10 -9.886438993852865 -6.19235781080747e+307 -> 307.79185604308338 -0.68218817692092071 + +-- values near 0 +logt0120 log10 2.2996867579227779e-308 6.7861840770939125e-312 -> -307.63833129662572 0.00012815668056362305 +logt0121 log10 6.9169190417774516e-323 -9.0414013188948118e-322 -> -321.04249706727148 -0.64902805353306059 +logt0122 log10 -1.5378064962914011e-316 1.8243628389354635e-310 -> -309.73888878263222 0.68218854299989429 +logt0123 log10 -2.3319898483706837e-321 -2.2358763941866371e-313 -> -312.65055220919641 -0.68218818145055538 +logt0124 log10 0.0 3.872770101081121e-315 -> -314.41197828323476 0.68218817692092071 +logt0125 log10 -0.0 9.6342800939043076e-322 -> -321.01618073175331 0.68218817692092071 +logt0126 log10 0.0 -2.266099393427834e-308 -> -307.64472104545649 -0.68218817692092071 +logt0127 log10 -0.0 -2.1184695673766626e-315 -> -314.67397777042407 -0.68218817692092071 +logt0128 log10 1.1363509854348671e-322 0.0 -> -321.94448750709819 0.0 +logt0129 log10 3.5572726500569751e-322 -0.0 -> -321.44888284668451 -0.0 +logt0130 log10 -2.3696071074040593e-310 0.0 -> -309.62532365619722 1.3643763538418414 +logt0131 log10 -2.813283897266934e-317 -0.0 -> -316.55078643961042 -1.3643763538418414 + +-- values near the unit circle +logt0200 log10 -0.59999999999999998 0.80000000000000004 -> 9.6432746655328709e-18 0.96165715756846815 +logt0201 log10 0.79999999999999993 0.60000000000000009 -> 2.6765463916147622e-33 0.2794689806475476 + +-- special values +logt1000 log10 -0.0 0.0 -> -inf 1.3643763538418414 divide-by-zero +logt1001 log10 0.0 0.0 -> -inf 0.0 divide-by-zero +logt1002 log10 0.0 inf -> inf 0.68218817692092071 +logt1003 log10 2.3 inf -> inf 0.68218817692092071 +logt1004 log10 -0.0 inf -> inf 0.68218817692092071 +logt1005 log10 -2.3 inf -> inf 0.68218817692092071 +logt1006 log10 0.0 nan -> nan nan +logt1007 log10 2.3 nan -> nan nan +logt1008 log10 -0.0 nan -> nan nan +logt1009 log10 -2.3 nan -> nan nan +logt1010 log10 -inf 0.0 -> inf 1.3643763538418414 +logt1011 log10 -inf 2.3 -> inf 1.3643763538418414 +logt1012 log10 inf 0.0 -> inf 0.0 +logt1013 log10 inf 2.3 -> inf 0.0 +logt1014 log10 -inf inf -> inf 1.0232822653813811 +logt1015 log10 inf inf -> inf 0.34109408846046035 +logt1016 log10 inf nan -> inf nan +logt1017 log10 -inf nan -> inf nan +logt1018 log10 nan 0.0 -> nan nan +logt1019 log10 nan 2.3 -> nan nan +logt1020 log10 nan inf -> inf nan +logt1021 log10 nan nan -> nan nan +logt1022 log10 -0.0 -0.0 -> -inf -1.3643763538418414 divide-by-zero +logt1023 log10 0.0 -0.0 -> -inf -0.0 divide-by-zero +logt1024 log10 0.0 -inf -> inf -0.68218817692092071 +logt1025 log10 2.3 -inf -> inf -0.68218817692092071 +logt1026 log10 -0.0 -inf -> inf -0.68218817692092071 +logt1027 log10 -2.3 -inf -> inf -0.68218817692092071 +logt1028 log10 -inf -0.0 -> inf -1.3643763538418414 +logt1029 log10 -inf -2.3 -> inf -1.3643763538418414 +logt1030 log10 inf -0.0 -> inf -0.0 +logt1031 log10 inf -2.3 -> inf -0.0 +logt1032 log10 -inf -inf -> inf -1.0232822653813811 +logt1033 log10 inf -inf -> inf -0.34109408846046035 +logt1034 log10 nan -0.0 -> nan nan +logt1035 log10 nan -2.3 -> nan nan +logt1036 log10 nan -inf -> inf nan + + +----------------------- +-- sqrt: Square root -- +----------------------- + +-- zeros +sqrt0000 sqrt 0.0 0.0 -> 0.0 0.0 +sqrt0001 sqrt 0.0 -0.0 -> 0.0 -0.0 +sqrt0002 sqrt -0.0 0.0 -> 0.0 0.0 +sqrt0003 sqrt -0.0 -0.0 -> 0.0 -0.0 + +-- values along both sides of real axis +sqrt0010 sqrt -9.8813129168249309e-324 0.0 -> 0.0 3.1434555694052576e-162 +sqrt0011 sqrt -9.8813129168249309e-324 -0.0 -> 0.0 -3.1434555694052576e-162 +sqrt0012 sqrt -1e-305 0.0 -> 0.0 3.1622776601683791e-153 +sqrt0013 sqrt -1e-305 -0.0 -> 0.0 -3.1622776601683791e-153 +sqrt0014 sqrt -1e-150 0.0 -> 0.0 9.9999999999999996e-76 +sqrt0015 sqrt -1e-150 -0.0 -> 0.0 -9.9999999999999996e-76 +sqrt0016 sqrt -9.9999999999999998e-17 0.0 -> 0.0 1e-08 +sqrt0017 sqrt -9.9999999999999998e-17 -0.0 -> 0.0 -1e-08 +sqrt0018 sqrt -0.001 0.0 -> 0.0 0.031622776601683791 +sqrt0019 sqrt -0.001 -0.0 -> 0.0 -0.031622776601683791 +sqrt0020 sqrt -0.57899999999999996 0.0 -> 0.0 0.76092049518987193 +sqrt0021 sqrt -0.57899999999999996 -0.0 -> 0.0 -0.76092049518987193 +sqrt0022 sqrt -0.99999999999999989 0.0 -> 0.0 0.99999999999999989 +sqrt0023 sqrt -0.99999999999999989 -0.0 -> 0.0 -0.99999999999999989 +sqrt0024 sqrt -1.0000000000000002 0.0 -> 0.0 1.0 +sqrt0025 sqrt -1.0000000000000002 -0.0 -> 0.0 -1.0 +sqrt0026 sqrt -1.0009999999999999 0.0 -> 0.0 1.000499875062461 +sqrt0027 sqrt -1.0009999999999999 -0.0 -> 0.0 -1.000499875062461 +sqrt0028 sqrt -2.0 0.0 -> 0.0 1.4142135623730951 +sqrt0029 sqrt -2.0 -0.0 -> 0.0 -1.4142135623730951 +sqrt0030 sqrt -23.0 0.0 -> 0.0 4.7958315233127191 +sqrt0031 sqrt -23.0 -0.0 -> 0.0 -4.7958315233127191 +sqrt0032 sqrt -10000000000000000.0 0.0 -> 0.0 100000000.0 +sqrt0033 sqrt -10000000000000000.0 -0.0 -> 0.0 -100000000.0 +sqrt0034 sqrt -9.9999999999999998e+149 0.0 -> 0.0 9.9999999999999993e+74 +sqrt0035 sqrt -9.9999999999999998e+149 -0.0 -> 0.0 -9.9999999999999993e+74 +sqrt0036 sqrt -1.0000000000000001e+299 0.0 -> 0.0 3.1622776601683796e+149 +sqrt0037 sqrt -1.0000000000000001e+299 -0.0 -> 0.0 -3.1622776601683796e+149 +sqrt0038 sqrt 9.8813129168249309e-324 0.0 -> 3.1434555694052576e-162 0.0 +sqrt0039 sqrt 9.8813129168249309e-324 -0.0 -> 3.1434555694052576e-162 -0.0 +sqrt0040 sqrt 1e-305 0.0 -> 3.1622776601683791e-153 0.0 +sqrt0041 sqrt 1e-305 -0.0 -> 3.1622776601683791e-153 -0.0 +sqrt0042 sqrt 1e-150 0.0 -> 9.9999999999999996e-76 0.0 +sqrt0043 sqrt 1e-150 -0.0 -> 9.9999999999999996e-76 -0.0 +sqrt0044 sqrt 9.9999999999999998e-17 0.0 -> 1e-08 0.0 +sqrt0045 sqrt 9.9999999999999998e-17 -0.0 -> 1e-08 -0.0 +sqrt0046 sqrt 0.001 0.0 -> 0.031622776601683791 0.0 +sqrt0047 sqrt 0.001 -0.0 -> 0.031622776601683791 -0.0 +sqrt0048 sqrt 0.57899999999999996 0.0 -> 0.76092049518987193 0.0 +sqrt0049 sqrt 0.57899999999999996 -0.0 -> 0.76092049518987193 -0.0 +sqrt0050 sqrt 0.99999999999999989 0.0 -> 0.99999999999999989 0.0 +sqrt0051 sqrt 0.99999999999999989 -0.0 -> 0.99999999999999989 -0.0 +sqrt0052 sqrt 1.0000000000000002 0.0 -> 1.0 0.0 +sqrt0053 sqrt 1.0000000000000002 -0.0 -> 1.0 -0.0 +sqrt0054 sqrt 1.0009999999999999 0.0 -> 1.000499875062461 0.0 +sqrt0055 sqrt 1.0009999999999999 -0.0 -> 1.000499875062461 -0.0 +sqrt0056 sqrt 2.0 0.0 -> 1.4142135623730951 0.0 +sqrt0057 sqrt 2.0 -0.0 -> 1.4142135623730951 -0.0 +sqrt0058 sqrt 23.0 0.0 -> 4.7958315233127191 0.0 +sqrt0059 sqrt 23.0 -0.0 -> 4.7958315233127191 -0.0 +sqrt0060 sqrt 10000000000000000.0 0.0 -> 100000000.0 0.0 +sqrt0061 sqrt 10000000000000000.0 -0.0 -> 100000000.0 -0.0 +sqrt0062 sqrt 9.9999999999999998e+149 0.0 -> 9.9999999999999993e+74 0.0 +sqrt0063 sqrt 9.9999999999999998e+149 -0.0 -> 9.9999999999999993e+74 -0.0 +sqrt0064 sqrt 1.0000000000000001e+299 0.0 -> 3.1622776601683796e+149 0.0 +sqrt0065 sqrt 1.0000000000000001e+299 -0.0 -> 3.1622776601683796e+149 -0.0 + +-- random inputs +sqrt0100 sqrt -0.34252542541549913 -223039880.15076211 -> 10560.300180587592 -10560.300196805192 +sqrt0101 sqrt -0.88790791393018909 -5.3307751730827402 -> 1.5027154613689004 -1.7737140896343291 +sqrt0102 sqrt -113916.89291310767 -0.018143374626153858 -> 2.6877817875351178e-05 -337.51576691038952 +sqrt0103 sqrt -0.63187172386197121 -0.26293913366617694 -> 0.16205707495266153 -0.81125471918761971 +sqrt0104 sqrt -0.058185169308906215 -2.3548312990430991 -> 1.0717660342420072 -1.0985752598086966 +sqrt0105 sqrt -1.0580584765935896 0.14400319259151736 -> 0.069837489270111242 1.030987755262468 +sqrt0106 sqrt -1.1667595947504932 0.11159711473953678 -> 0.051598531319315251 1.0813981705111229 +sqrt0107 sqrt -0.5123728411449906 0.026175433648339085 -> 0.018278026262418718 0.71603556293597614 +sqrt0108 sqrt -3.7453400060067228 1.0946500314809635 -> 0.27990088541692498 1.9554243814742367 +sqrt0109 sqrt -0.0027736121575097673 1.0367943000839817 -> 0.71903560338719175 0.72096172651250545 +sqrt0110 sqrt 1501.2559699453188 -1.1997325207283589 -> 38.746047664730959 -0.015481998720355024 +sqrt0111 sqrt 1.4830075326850578 -0.64100878436755349 -> 1.244712815741096 -0.25749264258434584 +sqrt0112 sqrt 0.095395618499734602 -0.48226565701639595 -> 0.54175904053472879 -0.44509239434231551 +sqrt0113 sqrt 0.50109185681863277 -0.54054037379892561 -> 0.7868179858332387 -0.34349772344520979 +sqrt0114 sqrt 0.98779807595367897 -0.00019848758437225191 -> 0.99388031770665153 -9.9854872279921968e-05 +sqrt0115 sqrt 11.845472380792259 0.0010051104581506761 -> 3.4417252072345397 0.00014601840612346451 +sqrt0116 sqrt 2.3558249686735975 0.25605157371744403 -> 1.5371278477386647 0.083288964575761404 +sqrt0117 sqrt 0.77584894123159098 1.0496420627016076 -> 1.0200744386390885 0.51449287568756552 +sqrt0118 sqrt 1.8961715669604893 0.34940793467158854 -> 1.3827991781411615 0.12634080935066902 +sqrt0119 sqrt 0.96025378316565801 0.69573224860140515 -> 1.0358710342209998 0.33581991658093457 + +-- values near 0 +sqrt0120 sqrt 7.3577938365086866e-313 8.1181408465112743e-319 -> 8.5777583531543516e-157 4.732087634251168e-163 +sqrt0121 sqrt 1.2406883874892108e-310 -5.1210133324269776e-312 -> 1.1140990057468052e-155 -2.2982756945349973e-157 +sqrt0122 sqrt -7.1145453001139502e-322 2.9561379244703735e-314 -> 1.2157585807480286e-157 1.2157586100077242e-157 +sqrt0123 sqrt -4.9963244206801218e-314 -8.4718424423690227e-319 -> 1.8950582312540437e-162 -2.2352459419578971e-157 +sqrt0124 sqrt 0.0 7.699553609385195e-318 -> 1.9620848107797476e-159 1.9620848107797476e-159 +sqrt0125 sqrt -0.0 3.3900826606499415e-309 -> 4.1170879639922327e-155 4.1170879639922327e-155 +sqrt0126 sqrt 0.0 -9.8907989772250828e-319 -> 7.032353438652342e-160 -7.032353438652342e-160 +sqrt0127 sqrt -0.0 -1.3722939367590908e-315 -> 2.6194407196566702e-158 -2.6194407196566702e-158 +sqrt0128 sqrt 7.9050503334599447e-323 0.0 -> 8.8910349979403099e-162 0.0 +sqrt0129 sqrt 1.8623241768349486e-309 -0.0 -> 4.3154654173506579e-155 -0.0 +sqrt0130 sqrt -2.665971134499887e-308 0.0 -> 0.0 1.6327801856036491e-154 +sqrt0131 sqrt -1.5477066694467245e-310 -0.0 -> 0.0 -1.2440685951533077e-155 + +-- inputs whose absolute value overflows +sqrt0140 sqrt 1.6999999999999999e+308 -1.6999999999999999e+308 -> 1.4325088230154573e+154 -5.9336458271212207e+153 +sqrt0141 sqrt -1.797e+308 -9.9999999999999999e+306 -> 3.7284476432057307e+152 -1.3410406899802901e+154 + +-- Additional real values (Jython) +sqrt0150 sqrt 1.7976931348623157e+308 0.0 -> 1.3407807929942596355e+154 0.0 +sqrt0151 sqrt 2.2250738585072014e-308 0.0 -> 1.4916681462400413487e-154 0.0 +sqrt0152 sqrt 5e-324 0.0 -> 2.2227587494850774834e-162 0.0 + +-- special values +sqrt1000 sqrt 0.0 0.0 -> 0.0 0.0 +sqrt1001 sqrt -0.0 0.0 -> 0.0 0.0 +sqrt1002 sqrt 0.0 inf -> inf inf +sqrt1003 sqrt 2.3 inf -> inf inf +sqrt1004 sqrt inf inf -> inf inf +sqrt1005 sqrt -0.0 inf -> inf inf +sqrt1006 sqrt -2.3 inf -> inf inf +sqrt1007 sqrt -inf inf -> inf inf +sqrt1008 sqrt nan inf -> inf inf +sqrt1009 sqrt 0.0 nan -> nan nan +sqrt1010 sqrt 2.3 nan -> nan nan +sqrt1011 sqrt -0.0 nan -> nan nan +sqrt1012 sqrt -2.3 nan -> nan nan +sqrt1013 sqrt -inf 0.0 -> 0.0 inf +sqrt1014 sqrt -inf 2.3 -> 0.0 inf +sqrt1015 sqrt inf 0.0 -> inf 0.0 +sqrt1016 sqrt inf 2.3 -> inf 0.0 +sqrt1017 sqrt -inf nan -> nan inf ignore-imag-sign +sqrt1018 sqrt inf nan -> inf nan +sqrt1019 sqrt nan 0.0 -> nan nan +sqrt1020 sqrt nan 2.3 -> nan nan +sqrt1021 sqrt nan nan -> nan nan +sqrt1022 sqrt 0.0 -0.0 -> 0.0 -0.0 +sqrt1023 sqrt -0.0 -0.0 -> 0.0 -0.0 +sqrt1024 sqrt 0.0 -inf -> inf -inf +sqrt1025 sqrt 2.3 -inf -> inf -inf +sqrt1026 sqrt inf -inf -> inf -inf +sqrt1027 sqrt -0.0 -inf -> inf -inf +sqrt1028 sqrt -2.3 -inf -> inf -inf +sqrt1029 sqrt -inf -inf -> inf -inf +sqrt1030 sqrt nan -inf -> inf -inf +sqrt1031 sqrt -inf -0.0 -> 0.0 -inf +sqrt1032 sqrt -inf -2.3 -> 0.0 -inf +sqrt1033 sqrt inf -0.0 -> inf -0.0 +sqrt1034 sqrt inf -2.3 -> inf -0.0 +sqrt1035 sqrt nan -0.0 -> nan nan +sqrt1036 sqrt nan -2.3 -> nan nan + + +-- For exp, cosh, sinh, tanh we limit tests to arguments whose +-- imaginary part is less than 10 in absolute value: most math +-- libraries have poor accuracy for (real) sine and cosine for +-- large arguments, and the accuracy of these complex functions +-- suffer correspondingly. +-- +-- Similarly, for cos, sin and tan we limit tests to arguments +-- with relatively small real part. + + +------------------------------- +-- exp: Exponential function -- +------------------------------- + +-- zeros +exp0000 exp 0.0 0.0 -> 1.0 0.0 +exp0001 exp 0.0 -0.0 -> 1.0 -0.0 +exp0002 exp -0.0 0.0 -> 1.0 0.0 +exp0003 exp -0.0 -0.0 -> 1.0 -0.0 + +-- random inputs +exp0004 exp -17.957359009564684 -1.108613895795274 -> 7.0869292576226611e-09 -1.4225929202377833e-08 +exp0005 exp -1.4456149663368642e-15 -0.75359817331772239 -> 0.72923148323917997 -0.68426708517419033 +exp0006 exp -0.76008654883512661 -0.46657235480105019 -> 0.41764393109928666 -0.21035108396792854 +exp0007 exp -5.7071614697735731 -2.3744161818115816e-11 -> 0.0033220890242068356 -7.8880219364953578e-14 +exp0008 exp -0.4653981327927097 -5.2236706667445587e-21 -> 0.62788507378216663 -3.2798648420026468e-21 +exp0009 exp -3.2444565242295518 1.1535625304243959 -> 0.015799936931457641 0.035644950380024749 +exp0010 exp -3.0651456337977727 0.87765086532391878 -> 0.029805595629855953 0.035882775180855669 +exp0011 exp -0.11080823753233926 0.96486386300873106 -> 0.50979112534376314 0.73575512419561562 +exp0012 exp -2.5629722598928648 0.019636235754708079 -> 0.077060452853917397 0.0015133717341137684 +exp0013 exp -3.3201709957983357e-10 1.2684017344487268 -> 0.29780699855434889 0.95462610007689186 +exp0014 exp 0.88767276057993272 -0.18953422986895557 -> 2.3859624049858095 -0.45771559132044426 +exp0015 exp 1.5738333486794742 -2.2576803075544328e-11 -> 4.8251091132458654 -1.0893553826776623e-10 +exp0016 exp 1.6408702341813795 -1.438879484380837 -> 0.6786733590689048 -5.1148284173168825 +exp0017 exp 1.820279424202033 -0.020812040370785722 -> 6.1722462896420902 -0.1284755888435051 +exp0018 exp 1.7273965735945873 -0.61140621328954947 -> 4.6067931898799976 -3.2294267694441308 +exp0019 exp 2.5606034306862995 0.098153136008435504 -> 12.881325889966629 1.2684184812864494 +exp0020 exp 10.280368619483029 3.4564622559748535 -> -27721.283321551502 -9028.9663215568835 +exp0021 exp 1.104007405129741e-155 0.21258803067317278 -> 0.97748813933531764 0.21099037290544478 +exp0022 exp 0.027364777809295172 0.00059226603500623363 -> 1.0277424518451876 0.0006086970181346579 +exp0023 exp 0.94356313429255245 3.418530463518592 -> -2.4712285695346194 -0.70242654900218349 + +-- cases where exp(z) representable, exp(z.real) not +exp0030 exp 710.0 0.78500000000000003 -> 1.5803016909637158e+308 1.5790437551806911e+308 +exp0031 exp 710.0 -0.78500000000000003 -> 1.5803016909637158e+308 -1.5790437551806911e+308 + +-- values for which exp(x) is subnormal, or underflows to 0 +exp0040 exp -735.0 0.78500000000000003 -> 4.3976783136329355e-320 4.3942198541120468e-320 +exp0041 exp -735.0 -2.3559999999999999 -> -4.3952079854037293e-320 -4.396690182341253e-320 +exp0042 exp -745.0 0.0 -> 4.9406564584124654e-324 0.0 +exp0043 exp -745.0 0.7 -> 0.0 0.0 +exp0044 exp -745.0 2.1 -> -0.0 0.0 +exp0045 exp -745.0 3.7 -> -0.0 -0.0 +exp0046 exp -745.0 5.3 -> 0.0 -0.0 + +-- values for which exp(z) overflows +exp0050 exp 710.0 0.0 -> inf 0.0 overflow +exp0051 exp 711.0 0.7 -> inf inf overflow +exp0052 exp 710.0 1.5 -> 1.5802653829857376e+307 inf overflow +exp0053 exp 710.0 1.6 -> -6.5231579995501372e+306 inf overflow +exp0054 exp 710.0 2.8 -> -inf 7.4836177417448528e+307 overflow + +-- Additional real values (Jython) +exp0070 exp 1e-08 0.0 -> 1.00000001000000005 0.0 +exp0071 exp 0.0003 0.0 -> 1.0003000450045003375 0.0 +exp0072 exp 0.2 0.0 -> 1.2214027581601698475 0.0 +exp0073 exp 1.0 0.0 -> 2.7182818284590452354 0.0 +exp0074 exp -1e-08 0.0 -> 0.99999999000000005 0.0 +exp0075 exp -0.0003 0.0 -> 0.99970004499550033751 0.0 +exp0076 exp -1.0 0.0 -> 0.3678794411714423216 0.0 +exp0077 exp 2.220446049250313e-16 0.0 -> 1.000000000000000222 0.0 +exp0078 exp -1.1102230246251565e-16 0.0 -> 0.99999999999999988898 0.0 +exp0079 exp 2.302585092994046 0.0 -> 10.000000000000002171 0.0 +exp0080 exp -2.302585092994046 0.0 -> 0.099999999999999978292 0.0 +exp0081 exp 709.7827 0.0 -> 1.7976699566638014654e+308 0.0 + +-- special values +exp1000 exp 0.0 0.0 -> 1.0 0.0 +exp1001 exp -0.0 0.0 -> 1.0 0.0 +exp1002 exp 0.0 inf -> nan nan invalid +exp1003 exp 2.3 inf -> nan nan invalid +exp1004 exp -0.0 inf -> nan nan invalid +exp1005 exp -2.3 inf -> nan nan invalid +exp1006 exp 0.0 nan -> nan nan +exp1007 exp 2.3 nan -> nan nan +exp1008 exp -0.0 nan -> nan nan +exp1009 exp -2.3 nan -> nan nan +exp1010 exp -inf 0.0 -> 0.0 0.0 +exp1011 exp -inf 1.4 -> 0.0 0.0 +exp1012 exp -inf 2.8 -> -0.0 0.0 +exp1013 exp -inf 4.2 -> -0.0 -0.0 +exp1014 exp -inf 5.6 -> 0.0 -0.0 +exp1015 exp -inf 7.0 -> 0.0 0.0 +exp1016 exp inf 0.0 -> inf 0.0 +exp1017 exp inf 1.4 -> inf inf +exp1018 exp inf 2.8 -> -inf inf +exp1019 exp inf 4.2 -> -inf -inf +exp1020 exp inf 5.6 -> inf -inf +exp1021 exp inf 7.0 -> inf inf +exp1022 exp -inf inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +exp1023 exp inf inf -> inf nan invalid ignore-real-sign +exp1024 exp -inf nan -> 0.0 0.0 ignore-real-sign ignore-imag-sign +exp1025 exp inf nan -> inf nan ignore-real-sign +exp1026 exp nan 0.0 -> nan 0.0 +exp1027 exp nan 2.3 -> nan nan +exp1028 exp nan inf -> nan nan +exp1029 exp nan nan -> nan nan +exp1030 exp 0.0 -0.0 -> 1.0 -0.0 +exp1031 exp -0.0 -0.0 -> 1.0 -0.0 +exp1032 exp 0.0 -inf -> nan nan invalid +exp1033 exp 2.3 -inf -> nan nan invalid +exp1034 exp -0.0 -inf -> nan nan invalid +exp1035 exp -2.3 -inf -> nan nan invalid +exp1036 exp -inf -0.0 -> 0.0 -0.0 +exp1037 exp -inf -1.4 -> 0.0 -0.0 +exp1038 exp -inf -2.8 -> -0.0 -0.0 +exp1039 exp -inf -4.2 -> -0.0 0.0 +exp1040 exp -inf -5.6 -> 0.0 0.0 +exp1041 exp -inf -7.0 -> 0.0 -0.0 +exp1042 exp inf -0.0 -> inf -0.0 +exp1043 exp inf -1.4 -> inf -inf +exp1044 exp inf -2.8 -> -inf -inf +exp1045 exp inf -4.2 -> -inf inf +exp1046 exp inf -5.6 -> inf inf +exp1047 exp inf -7.0 -> inf -inf +exp1048 exp -inf -inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +exp1049 exp inf -inf -> inf nan invalid ignore-real-sign +exp1050 exp nan -0.0 -> nan -0.0 +exp1051 exp nan -2.3 -> nan nan +exp1052 exp nan -inf -> nan nan + + +----------------------------- +-- cosh: Hyperbolic Cosine -- +----------------------------- + +-- zeros +cosh0000 cosh 0.0 0.0 -> 1.0 0.0 +cosh0001 cosh 0.0 -0.0 -> 1.0 -0.0 +cosh0002 cosh -0.0 0.0 -> 1.0 -0.0 +cosh0003 cosh -0.0 -0.0 -> 1.0 0.0 + +-- random inputs +cosh0004 cosh -0.85395264297414253 -8.8553756148671958 -> -1.1684340348021185 0.51842195359787435 +cosh0005 cosh -19.584904237211223 -0.066582627994906177 -> 159816812.23336992 10656776.050406246 +cosh0006 cosh -0.11072618401130772 -1.484820215073247 -> 0.086397164744949503 0.11054275637717284 +cosh0007 cosh -3.4764840250681752 -0.48440348288275276 -> 14.325931955190844 7.5242053548737955 +cosh0008 cosh -0.52047063604524602 -0.3603805382775585 -> 1.0653940354683802 0.19193293606252473 +cosh0009 cosh -1.39518962975995 0.0074738604700702906 -> 2.1417031027235969 -0.01415518712296308 +cosh0010 cosh -0.37107064757653541 0.14728085307856609 -> 1.0580601496776991 -0.055712531964568587 +cosh0011 cosh -5.8470200958739653 4.0021722388336292 -> -112.86220667618285 131.24734033545013 +cosh0012 cosh -0.1700261444851883 0.97167540135354513 -> 0.57208748253577946 -0.1410904820240203 +cosh0013 cosh -0.44042397902648783 1.0904791964139742 -> 0.50760322393058133 -0.40333966652010816 +cosh0014 cosh 0.052267552491867299 -3.8889011430644174 -> -0.73452303414639297 0.035540704833537134 +cosh0015 cosh 0.98000764177127453 -1.2548829247784097 -> 0.47220747341416142 -1.0879421432180316 +cosh0016 cosh 0.083594701222644008 -0.88847899930181284 -> 0.63279782419312613 -0.064954566816002285 +cosh0017 cosh 1.38173531783776 -0.43185040816732229 -> 1.9221663374671647 -0.78073830858849347 +cosh0018 cosh 0.57315681120148465 -0.22255760951027942 -> 1.1399733125173004 -0.1335512343605956 +cosh0019 cosh 1.8882512333062347 4.5024932182383797 -> -0.7041602065362691 -3.1573822131964615 +cosh0020 cosh 0.5618219206858317 0.92620452129575348 -> 0.69822380405378381 0.47309067471054522 +cosh0021 cosh 0.54361442847062591 0.64176483583018462 -> 0.92234462074193491 0.34167906495845501 +cosh0022 cosh 0.0014777403107920331 1.3682028122677661 -> 0.2012106963899549 0.001447518137863219 +cosh0023 cosh 2.218885944363501 2.0015727395883687 -> -1.94294321081968 4.1290269176083196 + +-- large real part +cosh0030 cosh 710.5 2.3519999999999999 -> -1.2967465239355998e+308 1.3076707908857333e+308 +cosh0031 cosh -710.5 0.69999999999999996 -> 1.4085466381392499e+308 -1.1864024666450239e+308 + +-- Additional real values (Jython) +cosh0050 cosh 1e-150 0.0 -> 1.0 0.0 +cosh0051 cosh 1e-18 0.0 -> 1.0 0.0 +cosh0052 cosh 1e-09 0.0 -> 1.0000000000000000005 0.0 +cosh0053 cosh 0.0003 0.0 -> 1.0000000450000003375 0.0 +cosh0054 cosh 0.2 0.0 -> 1.0200667556190758485 0.0 +cosh0055 cosh 1.0 0.0 -> 1.5430806348152437785 0.0 +cosh0056 cosh -1e-18 0.0 -> 1.0 0.0 +cosh0057 cosh -0.0003 0.0 -> 1.0000000450000003375 0.0 +cosh0058 cosh -1.0 0.0 -> 1.5430806348152437785 0.0 +cosh0059 cosh 1.3169578969248168 0.0 -> 2.0000000000000001504 0.0 +cosh0060 cosh -1.3169578969248168 0.0 -> 2.0000000000000001504 0.0 +cosh0061 cosh 17.328679513998633 0.0 -> 16777216.000000021938 0.0 +cosh0062 cosh 18.714973875118524 0.0 -> 67108864.000000043662 0.0 +cosh0063 cosh 709.7827 0.0 -> 8.9883497833190073272e+307 0.0 +cosh0064 cosh -709.7827 0.0 -> 8.9883497833190073272e+307 0.0 + +-- special values +cosh1000 cosh 0.0 0.0 -> 1.0 0.0 +cosh1001 cosh 0.0 inf -> nan 0.0 invalid ignore-imag-sign +cosh1002 cosh 0.0 nan -> nan 0.0 ignore-imag-sign +cosh1003 cosh 2.3 inf -> nan nan invalid +cosh1004 cosh 2.3 nan -> nan nan +cosh1005 cosh inf 0.0 -> inf 0.0 +cosh1006 cosh inf 1.4 -> inf inf +cosh1007 cosh inf 2.8 -> -inf inf +cosh1008 cosh inf 4.2 -> -inf -inf +cosh1009 cosh inf 5.6 -> inf -inf +cosh1010 cosh inf 7.0 -> inf inf +cosh1011 cosh inf inf -> inf nan invalid ignore-real-sign +cosh1012 cosh inf nan -> inf nan +cosh1013 cosh nan 0.0 -> nan 0.0 ignore-imag-sign +cosh1014 cosh nan 2.3 -> nan nan +cosh1015 cosh nan inf -> nan nan +cosh1016 cosh nan nan -> nan nan +cosh1017 cosh 0.0 -0.0 -> 1.0 -0.0 +cosh1018 cosh 0.0 -inf -> nan 0.0 invalid ignore-imag-sign +cosh1019 cosh 2.3 -inf -> nan nan invalid +cosh1020 cosh inf -0.0 -> inf -0.0 +cosh1021 cosh inf -1.4 -> inf -inf +cosh1022 cosh inf -2.8 -> -inf -inf +cosh1023 cosh inf -4.2 -> -inf inf +cosh1024 cosh inf -5.6 -> inf inf +cosh1025 cosh inf -7.0 -> inf -inf +cosh1026 cosh inf -inf -> inf nan invalid ignore-real-sign +cosh1027 cosh nan -0.0 -> nan 0.0 ignore-imag-sign +cosh1028 cosh nan -2.3 -> nan nan +cosh1029 cosh nan -inf -> nan nan +cosh1030 cosh -0.0 -0.0 -> 1.0 0.0 +cosh1031 cosh -0.0 -inf -> nan 0.0 invalid ignore-imag-sign +cosh1032 cosh -0.0 nan -> nan 0.0 ignore-imag-sign +cosh1033 cosh -2.3 -inf -> nan nan invalid +cosh1034 cosh -2.3 nan -> nan nan +cosh1035 cosh -inf -0.0 -> inf 0.0 +cosh1036 cosh -inf -1.4 -> inf inf +cosh1037 cosh -inf -2.8 -> -inf inf +cosh1038 cosh -inf -4.2 -> -inf -inf +cosh1039 cosh -inf -5.6 -> inf -inf +cosh1040 cosh -inf -7.0 -> inf inf +cosh1041 cosh -inf -inf -> inf nan invalid ignore-real-sign +cosh1042 cosh -inf nan -> inf nan +cosh1043 cosh -0.0 0.0 -> 1.0 -0.0 +cosh1044 cosh -0.0 inf -> nan 0.0 invalid ignore-imag-sign +cosh1045 cosh -2.3 inf -> nan nan invalid +cosh1046 cosh -inf 0.0 -> inf -0.0 +cosh1047 cosh -inf 1.4 -> inf -inf +cosh1048 cosh -inf 2.8 -> -inf -inf +cosh1049 cosh -inf 4.2 -> -inf inf +cosh1050 cosh -inf 5.6 -> inf inf +cosh1051 cosh -inf 7.0 -> inf -inf +cosh1052 cosh -inf inf -> inf nan invalid ignore-real-sign + + +--------------------------- +-- sinh: Hyperbolic Sine -- +--------------------------- + +-- zeros +sinh0000 sinh 0.0 0.0 -> 0.0 0.0 +sinh0001 sinh 0.0 -0.0 -> 0.0 -0.0 +sinh0002 sinh -0.0 0.0 -> -0.0 0.0 +sinh0003 sinh -0.0 -0.0 -> -0.0 -0.0 + +-- random inputs +sinh0004 sinh -17.282588091462742 -0.38187948694103546 -> -14867386.857248396 -5970648.6553516639 +sinh0005 sinh -343.91971203143208 -5.0172868877771525e-22 -> -1.1518691776521735e+149 -5.7792581214689021e+127 +sinh0006 sinh -14.178122253300922 -1.9387157579351293 -> 258440.37909034826 -670452.58500946441 +sinh0007 sinh -1.0343810581686239 -1.0970235266369905 -> -0.56070858278092739 -1.4098883258046697 +sinh0008 sinh -0.066126561416368204 -0.070461584169961872 -> -0.066010558700938124 -0.070557276738637542 +sinh0009 sinh -0.37630149150308484 3.3621734692162173 -> 0.37591118119332617 -0.23447115926369383 +sinh0010 sinh -0.049941960978670055 0.40323767020414625 -> -0.045955482136329009 0.3928878494430646 +sinh0011 sinh -16.647852603903715 0.0026852219129082098 -> -8492566.5739382561 22804.480671133562 +sinh0012 sinh -1.476625314303694 0.89473773116683386 -> -1.2982943334382224 1.7966593367791204 +sinh0013 sinh -422.36429577556913 0.10366634502307912 -> -1.3400321008920044e+183 1.3941600948045599e+182 +sinh0014 sinh 0.09108340745641981 -0.40408227416070353 -> 0.083863724802237902 -0.39480716553935602 +sinh0015 sinh 2.036064132067386 -2.6831729961386239 -> -3.37621124363175 -1.723868330002817 +sinh0016 sinh 2.5616717223063317 -0.0078978498622717767 -> 6.4399415853815869 -0.051472264400722133 +sinh0017 sinh 0.336804011985188 -6.5654622971649337 -> 0.32962499307574578 -0.29449170159995197 +sinh0018 sinh 0.23774603755649693 -0.92467195799232049 -> 0.14449839490603389 -0.82109449053556793 +sinh0019 sinh 0.0011388273541465494 1.9676196882949855 -> -0.00044014605389634999 0.92229398407098806 +sinh0020 sinh 3.2443870105663759 0.8054287559616895 -> 8.8702890778527426 9.2610748597042196 +sinh0021 sinh 0.040628908857054738 0.098206391190944958 -> 0.04044426841671233 0.098129544739707392 +sinh0022 sinh 4.7252283918217696e-30 9.1198155642656697 -> -4.5071980561644404e-30 0.30025730701661713 +sinh0023 sinh 0.043713693678420068 0.22512549887532657 -> 0.042624198673416713 0.22344201231217961 + +-- large real part +sinh0030 sinh 710.5 -2.3999999999999999 -> -1.3579970564885919e+308 -1.24394470907798e+308 +sinh0031 sinh -710.5 0.80000000000000004 -> -1.2830671601735164e+308 1.3210954193997678e+308 + +-- Additional real values (Jython) +sinh0050 sinh 1e-100 0.0 -> 1.00000000000000002e-100 0.0 +sinh0051 sinh 5e-17 0.0 -> 4.9999999999999998955e-17 0.0 +sinh0052 sinh 1e-16 0.0 -> 9.999999999999999791e-17 0.0 +sinh0053 sinh 3.7e-08 0.0 -> 3.7000000000000008885e-8 0.0 +sinh0054 sinh 0.001 0.0 -> 0.0010000001666666750208 0.0 +sinh0055 sinh 0.2 0.0 -> 0.20133600254109399895 0.0 +sinh0056 sinh 1.0 0.0 -> 1.1752011936438014569 0.0 +sinh0057 sinh -3.7e-08 0.0 -> -3.7000000000000008885e-8 0.0 +sinh0058 sinh -0.001 0.0 -> -0.0010000001666666750208 0.0 +sinh0059 sinh -1.0 0.0 -> -1.1752011936438014569 0.0 +sinh0060 sinh 1.4436354751788103 0.0 -> 1.9999999999999999078 0.0 +sinh0061 sinh -1.4436354751788103 0.0 -> -1.9999999999999999078 0.0 +sinh0062 sinh 17.328679513998633 0.0 -> 16777215.999999992136 0.0 +sinh0063 sinh 18.714973875118524 0.0 -> 67108864.000000036211 0.0 +sinh0064 sinh 709.7827 0.0 -> 8.9883497833190073272e+307 0.0 +sinh0065 sinh -709.7827 0.0 -> -8.9883497833190073272e+307 0.0 + +-- special values +sinh1000 sinh 0.0 0.0 -> 0.0 0.0 +sinh1001 sinh 0.0 inf -> 0.0 nan invalid ignore-real-sign +sinh1002 sinh 0.0 nan -> 0.0 nan ignore-real-sign +sinh1003 sinh 2.3 inf -> nan nan invalid +sinh1004 sinh 2.3 nan -> nan nan +sinh1005 sinh inf 0.0 -> inf 0.0 +sinh1006 sinh inf 1.4 -> inf inf +sinh1007 sinh inf 2.8 -> -inf inf +sinh1008 sinh inf 4.2 -> -inf -inf +sinh1009 sinh inf 5.6 -> inf -inf +sinh1010 sinh inf 7.0 -> inf inf +sinh1011 sinh inf inf -> inf nan invalid ignore-real-sign +sinh1012 sinh inf nan -> inf nan ignore-real-sign +sinh1013 sinh nan 0.0 -> nan 0.0 +sinh1014 sinh nan 2.3 -> nan nan +sinh1015 sinh nan inf -> nan nan +sinh1016 sinh nan nan -> nan nan +sinh1017 sinh 0.0 -0.0 -> 0.0 -0.0 +sinh1018 sinh 0.0 -inf -> 0.0 nan invalid ignore-real-sign +sinh1019 sinh 2.3 -inf -> nan nan invalid +sinh1020 sinh inf -0.0 -> inf -0.0 +sinh1021 sinh inf -1.4 -> inf -inf +sinh1022 sinh inf -2.8 -> -inf -inf +sinh1023 sinh inf -4.2 -> -inf inf +sinh1024 sinh inf -5.6 -> inf inf +sinh1025 sinh inf -7.0 -> inf -inf +sinh1026 sinh inf -inf -> inf nan invalid ignore-real-sign +sinh1027 sinh nan -0.0 -> nan -0.0 +sinh1028 sinh nan -2.3 -> nan nan +sinh1029 sinh nan -inf -> nan nan +sinh1030 sinh -0.0 -0.0 -> -0.0 -0.0 +sinh1031 sinh -0.0 -inf -> 0.0 nan invalid ignore-real-sign +sinh1032 sinh -0.0 nan -> 0.0 nan ignore-real-sign +sinh1033 sinh -2.3 -inf -> nan nan invalid +sinh1034 sinh -2.3 nan -> nan nan +sinh1035 sinh -inf -0.0 -> -inf -0.0 +sinh1036 sinh -inf -1.4 -> -inf -inf +sinh1037 sinh -inf -2.8 -> inf -inf +sinh1038 sinh -inf -4.2 -> inf inf +sinh1039 sinh -inf -5.6 -> -inf inf +sinh1040 sinh -inf -7.0 -> -inf -inf +sinh1041 sinh -inf -inf -> inf nan invalid ignore-real-sign +sinh1042 sinh -inf nan -> inf nan ignore-real-sign +sinh1043 sinh -0.0 0.0 -> -0.0 0.0 +sinh1044 sinh -0.0 inf -> 0.0 nan invalid ignore-real-sign +sinh1045 sinh -2.3 inf -> nan nan invalid +sinh1046 sinh -inf 0.0 -> -inf 0.0 +sinh1047 sinh -inf 1.4 -> -inf inf +sinh1048 sinh -inf 2.8 -> inf inf +sinh1049 sinh -inf 4.2 -> inf -inf +sinh1050 sinh -inf 5.6 -> -inf -inf +sinh1051 sinh -inf 7.0 -> -inf inf +sinh1052 sinh -inf inf -> inf nan invalid ignore-real-sign + + +------------------------------ +-- tanh: Hyperbolic Tangent -- +------------------------------ + +-- zeros +tanh0000 tanh 0.0 0.0 -> 0.0 0.0 +tanh0001 tanh 0.0 -0.0 -> 0.0 -0.0 +tanh0002 tanh -0.0 0.0 -> -0.0 0.0 +tanh0003 tanh -0.0 -0.0 -> -0.0 -0.0 + +-- random inputs +tanh0004 tanh -21.200500450664993 -1.6970729480342996 -> -1.0 1.9241352344849399e-19 +tanh0005 tanh -0.34158771504251928 -8.0848504951747131 -> -2.123711225855613 1.2827526782026006 +tanh0006 tanh -15.454144725193689 -0.23619582288265617 -> -0.99999999999993283 -3.4336684248260036e-14 +tanh0007 tanh -7.6103163119661952 -0.7802748320307008 -> -0.99999999497219438 -4.9064845343755437e-07 +tanh0008 tanh -0.15374717235792129 -0.6351086327306138 -> -0.23246081703561869 -0.71083467433910219 +tanh0009 tanh -0.49101115474392465 0.09723001264886301 -> -0.45844445715492133 0.077191158541805888 +tanh0010 tanh -0.10690612157664491 2.861612800856395 -> -0.11519761626257358 -0.28400488355647507 +tanh0011 tanh -0.91505774192066702 1.5431174597727007 -> -1.381109893068114 0.025160819663709356 +tanh0012 tanh -0.057433367093792223 0.35491159541246459 -> -0.065220499046696953 0.36921788332369498 +tanh0013 tanh -1.3540418621233514 0.18969415642242535 -> -0.88235642861151387 0.043764069984411721 +tanh0014 tanh 0.94864783961003529 -0.11333689578867717 -> 0.74348401861861368 -0.051271042543855221 +tanh0015 tanh 1.9591698133845488 -0.0029654444904578339 -> 0.9610270776968135 -0.00022664240049212933 +tanh0016 tanh 1.0949715796669197 -0.24706642853984456 -> 0.81636574501369386 -0.087767436914149954 +tanh0017 tanh 5770428.2113731047 -3.7160580339833165 -> 1.0 -0.0 +tanh0018 tanh 1.5576782321399629 -1.0357943787966468 -> 1.0403002384895388 -0.081126347894671463 +tanh0019 tanh 0.62378536230552961 2.3471393579560216 -> 0.85582499238960363 -0.53569473646842869 +tanh0020 tanh 17.400628602508025 9.3987059533841979 -> 0.99999999999999845 -8.0175867720530832e-17 +tanh0021 tanh 0.15026177509871896 0.50630349159505472 -> 0.19367536571827768 0.53849847858853661 +tanh0022 tanh 0.57433977530711167 1.0071604546265627 -> 1.0857848159262844 0.69139213955872214 +tanh0023 tanh 0.16291181500449456 0.006972810241567544 -> 0.16149335907551157 0.0067910772903467817 + +-- large real part +tanh0030 tanh 710 0.13 -> 1.0 0.0 +tanh0031 tanh -711 7.4000000000000004 -> -1.0 0.0 +tanh0032 tanh 1000 -2.3199999999999998 -> 1.0 0.0 +tanh0033 tanh -1.0000000000000001e+300 -9.6699999999999999 -> -1.0 -0.0 + +-- Additional real values (Jython) +tanh0050 tanh 1e-100 0.0 -> 1.00000000000000002e-100 0.0 +tanh0051 tanh 5e-17 0.0 -> 4.9999999999999998955e-17 0.0 +tanh0052 tanh 1e-16 0.0 -> 9.999999999999999791e-17 0.0 +tanh0053 tanh 3.7e-08 0.0 -> 3.6999999999999983559e-8 0.0 +tanh0054 tanh 0.001 0.0 -> 0.00099999966666680002076 0.0 +tanh0055 tanh 0.2 0.0 -> 0.19737532022490401141 0.0 +tanh0056 tanh 1.0 0.0 -> 0.76159415595576488812 0.0 +tanh0057 tanh -3.7e-08 0.0 -> -3.6999999999999983559e-8 0.0 +tanh0058 tanh -0.001 0.0 -> -0.00099999966666680002076 0.0 +tanh0059 tanh -1.0 0.0 -> -0.76159415595576488812 0.0 +tanh0060 tanh 0.5493061443340549 0.0 -> 0.50000000000000003402 0.0 +tanh0061 tanh -0.5493061443340549 0.0 -> -0.50000000000000003402 0.0 +tanh0062 tanh 17.328679513998633 0.0 -> 0.99999999999999822364 0.0 +tanh0063 tanh 18.714973875118524 0.0 -> 0.99999999999999988898 0.0 +tanh0064 tanh 711 0.0 -> 1.0 0.0 +tanh0065 tanh 1.797e+308 0.0 -> 1.0 0.0 + +--special values +tanh1000 tanh 0.0 0.0 -> 0.0 0.0 +tanh1001 tanh 0.0 inf -> nan nan invalid +tanh1002 tanh 2.3 inf -> nan nan invalid +tanh1003 tanh 0.0 nan -> nan nan +tanh1004 tanh 2.3 nan -> nan nan +tanh1005 tanh inf 0.0 -> 1.0 0.0 +tanh1006 tanh inf 0.7 -> 1.0 0.0 +tanh1007 tanh inf 1.4 -> 1.0 0.0 +tanh1008 tanh inf 2.1 -> 1.0 -0.0 +tanh1009 tanh inf 2.8 -> 1.0 -0.0 +tanh1010 tanh inf 3.5 -> 1.0 0.0 +tanh1011 tanh inf inf -> 1.0 0.0 ignore-imag-sign +tanh1012 tanh inf nan -> 1.0 0.0 ignore-imag-sign +tanh1013 tanh nan 0.0 -> nan 0.0 +tanh1014 tanh nan 2.3 -> nan nan +tanh1015 tanh nan inf -> nan nan +tanh1016 tanh nan nan -> nan nan +tanh1017 tanh 0.0 -0.0 -> 0.0 -0.0 +tanh1018 tanh 0.0 -inf -> nan nan invalid +tanh1019 tanh 2.3 -inf -> nan nan invalid +tanh1020 tanh inf -0.0 -> 1.0 -0.0 +tanh1021 tanh inf -0.7 -> 1.0 -0.0 +tanh1022 tanh inf -1.4 -> 1.0 -0.0 +tanh1023 tanh inf -2.1 -> 1.0 0.0 +tanh1024 tanh inf -2.8 -> 1.0 0.0 +tanh1025 tanh inf -3.5 -> 1.0 -0.0 +tanh1026 tanh inf -inf -> 1.0 0.0 ignore-imag-sign +tanh1027 tanh nan -0.0 -> nan -0.0 +tanh1028 tanh nan -2.3 -> nan nan +tanh1029 tanh nan -inf -> nan nan +tanh1030 tanh -0.0 -0.0 -> -0.0 -0.0 +tanh1031 tanh -0.0 -inf -> nan nan invalid +tanh1032 tanh -2.3 -inf -> nan nan invalid +tanh1033 tanh -0.0 nan -> nan nan +tanh1034 tanh -2.3 nan -> nan nan +tanh1035 tanh -inf -0.0 -> -1.0 -0.0 +tanh1036 tanh -inf -0.7 -> -1.0 -0.0 +tanh1037 tanh -inf -1.4 -> -1.0 -0.0 +tanh1038 tanh -inf -2.1 -> -1.0 0.0 +tanh1039 tanh -inf -2.8 -> -1.0 0.0 +tanh1040 tanh -inf -3.5 -> -1.0 -0.0 +tanh1041 tanh -inf -inf -> -1.0 0.0 ignore-imag-sign +tanh1042 tanh -inf nan -> -1.0 0.0 ignore-imag-sign +tanh1043 tanh -0.0 0.0 -> -0.0 0.0 +tanh1044 tanh -0.0 inf -> nan nan invalid +tanh1045 tanh -2.3 inf -> nan nan invalid +tanh1046 tanh -inf 0.0 -> -1.0 0.0 +tanh1047 tanh -inf 0.7 -> -1.0 0.0 +tanh1048 tanh -inf 1.4 -> -1.0 0.0 +tanh1049 tanh -inf 2.1 -> -1.0 -0.0 +tanh1050 tanh -inf 2.8 -> -1.0 -0.0 +tanh1051 tanh -inf 3.5 -> -1.0 0.0 +tanh1052 tanh -inf inf -> -1.0 0.0 ignore-imag-sign + + +----------------- +-- cos: Cosine -- +----------------- + +-- zeros +cos0000 cos 0.0 0.0 -> 1.0 -0.0 +cos0001 cos 0.0 -0.0 -> 1.0 0.0 +cos0002 cos -0.0 0.0 -> 1.0 0.0 +cos0003 cos -0.0 -0.0 -> 1.0 -0.0 + +-- random inputs +cos0004 cos -2.0689194692073034 -0.0016802181751734313 -> -0.47777827208561469 -0.0014760401501695971 +cos0005 cos -0.4209627318177977 -1.8238516774258027 -> 2.9010402201444108 -1.2329207042329617 +cos0006 cos -1.9402181630694557 -2.9751857392891217 -> -3.5465459297970985 -9.1119163586282248 +cos0007 cos -3.3118320290191616 -0.87871302909286142 -> -1.3911528636565498 0.16878141517391701 +cos0008 cos -4.9540404623376872 -0.57949232239026827 -> 0.28062445586552065 0.59467861308508008 +cos0009 cos -0.45374584316245026 1.3950283448373935 -> 1.9247665574290578 0.83004572204761107 +cos0010 cos -0.42578172040176843 1.2715881615413049 -> 1.7517161459489148 0.67863902697363332 +cos0011 cos -0.13862985354300136 0.43587635877670328 -> 1.0859880290361912 0.062157548146672272 +cos0012 cos -0.11073221308966584 9.9384082307326475e-15 -> 0.99387545040722947 1.0982543264065479e-15 +cos0013 cos -1.5027633662054623e-07 0.0069668060249955498 -> 1.0000242682912412 1.0469545565660995e-09 +cos0014 cos 4.9728645490503052 -0.00027479808860952822 -> 0.25754011731975501 -0.00026552849549083186 +cos0015 cos 7.81969303486719 -0.79621523445878783 -> 0.045734882501585063 0.88253139933082991 +cos0016 cos 0.13272421880766716 -0.74668445308718201 -> 1.2806012244432847 0.10825373267437005 +cos0017 cos 4.2396521985973274 -2.2178848380884881 -> -2.1165117057056855 -4.0416492444641401 +cos0018 cos 1.1622206624927296 -0.50400115461197081 -> 0.44884072613370379 0.4823469915034318 +cos0019 cos 1.628772864620884e-08 0.58205705428979282 -> 1.1742319995791435 -1.0024839481956604e-08 +cos0020 cos 2.6385212606111241 2.9886107100937296 -> -8.7209475927161417 -4.7748352107199796 +cos0021 cos 4.8048375263775256 0.0062248852898515658 -> 0.092318702015846243 0.0061983430422306142 +cos0022 cos 7.9914515433858515 0.71659966615501436 -> -0.17375439906936566 -0.77217043527294582 +cos0023 cos 0.45124351152540226 1.6992693993812158 -> 2.543477948972237 -1.1528193694875477 + +-- Additional real values (Jython) +cos0050 cos 1e-150 0.0 -> 1.0 0.0 +cos0051 cos 1e-18 0.0 -> 1.0 0.0 +cos0052 cos 1e-09 0.0 -> 0.9999999999999999995 0.0 +cos0053 cos 0.0003 0.0 -> 0.9999999550000003375 0.0 +cos0054 cos 0.2 0.0 -> 0.98006657784124162892 0.0 +cos0055 cos 1.0 0.0 -> 0.5403023058681397174 0.0 +cos0056 cos -1e-18 0.0 -> 1.0 0.0 +cos0057 cos -0.0003 0.0 -> 0.9999999550000003375 0.0 +cos0058 cos -1.0 0.0 -> 0.5403023058681397174 0.0 +cos0059 cos 1.0471975511965976 0.0 -> 0.50000000000000009945 0.0 +cos0060 cos 2.5707963267948966 0.0 -> -0.84147098480789647357 0.0 +cos0061 cos -2.5707963267948966 0.0 -> -0.84147098480789647357 0.0 +cos0062 cos 18 0.0 -> 0.66031670824408014482 0.0 +cos0063 cos 18.0 0.0 -> 0.66031670824408014482 0.0 + +-- special values +cos1000 cos -0.0 0.0 -> 1.0 0.0 +cos1001 cos -inf 0.0 -> nan 0.0 invalid ignore-imag-sign +cos1002 cos nan 0.0 -> nan 0.0 ignore-imag-sign +cos1003 cos -inf 2.2999999999999998 -> nan nan invalid +cos1004 cos nan 2.2999999999999998 -> nan nan +cos1005 cos -0.0 inf -> inf 0.0 +cos1006 cos -1.3999999999999999 inf -> inf inf +cos1007 cos -2.7999999999999998 inf -> -inf inf +cos1008 cos -4.2000000000000002 inf -> -inf -inf +cos1009 cos -5.5999999999999996 inf -> inf -inf +cos1010 cos -7.0 inf -> inf inf +cos1011 cos -inf inf -> inf nan invalid ignore-real-sign +cos1012 cos nan inf -> inf nan +cos1013 cos -0.0 nan -> nan 0.0 ignore-imag-sign +cos1014 cos -2.2999999999999998 nan -> nan nan +cos1015 cos -inf nan -> nan nan +cos1016 cos nan nan -> nan nan +cos1017 cos 0.0 0.0 -> 1.0 -0.0 +cos1018 cos inf 0.0 -> nan 0.0 invalid ignore-imag-sign +cos1019 cos inf 2.2999999999999998 -> nan nan invalid +cos1020 cos 0.0 inf -> inf -0.0 +cos1021 cos 1.3999999999999999 inf -> inf -inf +cos1022 cos 2.7999999999999998 inf -> -inf -inf +cos1023 cos 4.2000000000000002 inf -> -inf inf +cos1024 cos 5.5999999999999996 inf -> inf inf +cos1025 cos 7.0 inf -> inf -inf +cos1026 cos inf inf -> inf nan invalid ignore-real-sign +cos1027 cos 0.0 nan -> nan 0.0 ignore-imag-sign +cos1028 cos 2.2999999999999998 nan -> nan nan +cos1029 cos inf nan -> nan nan +cos1030 cos 0.0 -0.0 -> 1.0 0.0 +cos1031 cos inf -0.0 -> nan 0.0 invalid ignore-imag-sign +cos1032 cos nan -0.0 -> nan 0.0 ignore-imag-sign +cos1033 cos inf -2.2999999999999998 -> nan nan invalid +cos1034 cos nan -2.2999999999999998 -> nan nan +cos1035 cos 0.0 -inf -> inf 0.0 +cos1036 cos 1.3999999999999999 -inf -> inf inf +cos1037 cos 2.7999999999999998 -inf -> -inf inf +cos1038 cos 4.2000000000000002 -inf -> -inf -inf +cos1039 cos 5.5999999999999996 -inf -> inf -inf +cos1040 cos 7.0 -inf -> inf inf +cos1041 cos inf -inf -> inf nan invalid ignore-real-sign +cos1042 cos nan -inf -> inf nan +cos1043 cos -0.0 -0.0 -> 1.0 -0.0 +cos1044 cos -inf -0.0 -> nan 0.0 invalid ignore-imag-sign +cos1045 cos -inf -2.2999999999999998 -> nan nan invalid +cos1046 cos -0.0 -inf -> inf -0.0 +cos1047 cos -1.3999999999999999 -inf -> inf -inf +cos1048 cos -2.7999999999999998 -inf -> -inf -inf +cos1049 cos -4.2000000000000002 -inf -> -inf inf +cos1050 cos -5.5999999999999996 -inf -> inf inf +cos1051 cos -7.0 -inf -> inf -inf +cos1052 cos -inf -inf -> inf nan invalid ignore-real-sign + + +--------------- +-- sin: Sine -- +--------------- + +-- zeros +sin0000 sin 0.0 0.0 -> 0.0 0.0 +sin0001 sin 0.0 -0.0 -> 0.0 -0.0 +sin0002 sin -0.0 0.0 -> -0.0 0.0 +sin0003 sin -0.0 -0.0 -> -0.0 -0.0 + +-- random inputs +sin0004 sin -0.18691829163163759 -0.74388741985507034 -> -0.2396636733773444 -0.80023231101856751 +sin0005 sin -0.45127453702459158 -461.81339920716164 -> -7.9722299331077877e+199 -1.6450205811004628e+200 +sin0006 sin -0.47669228345768921 -2.7369936564987514 -> -3.557238022267124 -6.8308030771226615 +sin0007 sin -0.31024285525950857 -1.4869219939188296 -> -0.70972676047175209 -1.9985029635426839 +sin0008 sin -4.4194573407025608 -1.405999210989288 -> 2.0702480800802685 0.55362250792180601 +sin0009 sin -1.7810832046434898e-05 0.0016439555384379083 -> -1.7810856113185261e-05 0.0016439562786668375 +sin0010 sin -0.8200017874897666 0.61724876887771929 -> -0.8749078195948865 0.44835295550987758 +sin0011 sin -1.4536502806107114 0.63998575534150415 -> -1.2035709929437679 0.080012187489163708 +sin0012 sin -2.2653412155506079 0.13172760685583729 -> -0.77502093809190431 -0.084554426868229532 +sin0013 sin -0.02613983069491858 0.18404766597776073 -> -0.026580778863127943 0.18502525396735642 +sin0014 sin 1.5743065001054617 -0.53125574272642029 -> 1.1444596332092725 0.0019537598099352077 +sin0015 sin 7.3833101791283289e-20 -0.16453221324236217 -> 7.4834720674379429e-20 -0.16527555646466915 +sin0016 sin 0.34763834641254038 -2.8377416421089565 -> 2.918883541504663 -8.0002718053250224 +sin0017 sin 0.077105785180421563 -0.090056027316200674 -> 0.077341973814471304 -0.089909869380524587 +sin0018 sin 3.9063227798142329e-17 -0.05954098654295524 -> 3.9132490348956512e-17 -0.059576172859837351 +sin0019 sin 0.57333917932544598 8.7785221430594696e-06 -> 0.54244029338302935 7.3747869125301368e-06 +sin0020 sin 0.024861722816513169 0.33044620756118515 -> 0.026228801369651 0.3363889671570689 +sin0021 sin 1.4342727387492671 0.81361889790284347 -> 1.3370960060947923 0.12336137961387163 +sin0022 sin 1.1518087354403725 4.8597235966150558 -> 58.919141989603041 26.237003403758852 +sin0023 sin 0.00087773078406649192 34.792379211312095 -> 565548145569.38245 644329685822700.62 + +-- Additional real values (Jython) +sin0050 sin 1e-100 0.0 -> 1.00000000000000002e-100 0.0 +sin0051 sin 3.7e-08 0.0 -> 3.6999999999999992001e-8 0.0 +sin0052 sin 0.001 0.0 -> 0.00099999983333334168748 0.0 +sin0053 sin 0.2 0.0 -> 0.19866933079506122634 0.0 +sin0054 sin 1.0 0.0 -> 0.84147098480789650665 0.0 +sin0055 sin -3.7e-08 0.0 -> -3.6999999999999992001e-8 0.0 +sin0056 sin -0.001 0.0 -> -0.00099999983333334168748 0.0 +sin0057 sin -1.0 0.0 -> -0.84147098480789650665 0.0 +sin0058 sin 0.5235987755982989 0.0 -> 0.50000000000000004642 0.0 +sin0059 sin -0.5235987755982989 0.0 -> -0.50000000000000004642 0.0 +sin0060 sin 2.6179938779914944 0.0 -> 0.49999999999999996018 0.0 +sin0061 sin -2.6179938779914944 0.0 -> -0.49999999999999996018 0.0 + +-- special values +sin1000 sin -0.0 0.0 -> -0.0 0.0 +sin1001 sin -inf 0.0 -> nan 0.0 invalid ignore-imag-sign +sin1002 sin nan 0.0 -> nan 0.0 ignore-imag-sign +sin1003 sin -inf 2.2999999999999998 -> nan nan invalid +sin1004 sin nan 2.2999999999999998 -> nan nan +sin1005 sin -0.0 inf -> -0.0 inf +sin1006 sin -1.3999999999999999 inf -> -inf inf +sin1007 sin -2.7999999999999998 inf -> -inf -inf +sin1008 sin -4.2000000000000002 inf -> inf -inf +sin1009 sin -5.5999999999999996 inf -> inf inf +sin1010 sin -7.0 inf -> -inf inf +sin1011 sin -inf inf -> nan inf invalid ignore-imag-sign +sin1012 sin nan inf -> nan inf ignore-imag-sign +sin1013 sin -0.0 nan -> -0.0 nan +sin1014 sin -2.2999999999999998 nan -> nan nan +sin1015 sin -inf nan -> nan nan +sin1016 sin nan nan -> nan nan +sin1017 sin 0.0 0.0 -> 0.0 0.0 +sin1018 sin inf 0.0 -> nan 0.0 invalid ignore-imag-sign +sin1019 sin inf 2.2999999999999998 -> nan nan invalid +sin1020 sin 0.0 inf -> 0.0 inf +sin1021 sin 1.3999999999999999 inf -> inf inf +sin1022 sin 2.7999999999999998 inf -> inf -inf +sin1023 sin 4.2000000000000002 inf -> -inf -inf +sin1024 sin 5.5999999999999996 inf -> -inf inf +sin1025 sin 7.0 inf -> inf inf +sin1026 sin inf inf -> nan inf invalid ignore-imag-sign +sin1027 sin 0.0 nan -> 0.0 nan +sin1028 sin 2.2999999999999998 nan -> nan nan +sin1029 sin inf nan -> nan nan +sin1030 sin 0.0 -0.0 -> 0.0 -0.0 +sin1031 sin inf -0.0 -> nan 0.0 invalid ignore-imag-sign +sin1032 sin nan -0.0 -> nan 0.0 ignore-imag-sign +sin1033 sin inf -2.2999999999999998 -> nan nan invalid +sin1034 sin nan -2.2999999999999998 -> nan nan +sin1035 sin 0.0 -inf -> 0.0 -inf +sin1036 sin 1.3999999999999999 -inf -> inf -inf +sin1037 sin 2.7999999999999998 -inf -> inf inf +sin1038 sin 4.2000000000000002 -inf -> -inf inf +sin1039 sin 5.5999999999999996 -inf -> -inf -inf +sin1040 sin 7.0 -inf -> inf -inf +sin1041 sin inf -inf -> nan inf invalid ignore-imag-sign +sin1042 sin nan -inf -> nan inf ignore-imag-sign +sin1043 sin -0.0 -0.0 -> -0.0 -0.0 +sin1044 sin -inf -0.0 -> nan 0.0 invalid ignore-imag-sign +sin1045 sin -inf -2.2999999999999998 -> nan nan invalid +sin1046 sin -0.0 -inf -> -0.0 -inf +sin1047 sin -1.3999999999999999 -inf -> -inf -inf +sin1048 sin -2.7999999999999998 -inf -> -inf inf +sin1049 sin -4.2000000000000002 -inf -> inf inf +sin1050 sin -5.5999999999999996 -inf -> inf -inf +sin1051 sin -7.0 -inf -> -inf -inf +sin1052 sin -inf -inf -> nan inf invalid ignore-imag-sign + + +------------------ +-- tan: Tangent -- +------------------ + +-- zeros +tan0000 tan 0.0 0.0 -> 0.0 0.0 +tan0001 tan 0.0 -0.0 -> 0.0 -0.0 +tan0002 tan -0.0 0.0 -> -0.0 0.0 +tan0003 tan -0.0 -0.0 -> -0.0 -0.0 + +-- random inputs +tan0004 tan -0.56378561833861074 -1.7110276237187664e+73 -> -0.0 -1.0 +tan0005 tan -3.5451633993471915e-12 -2.855471863564059 -> -4.6622441304889575e-14 -0.99340273843093951 +tan0006 tan -2.502442719638696 -0.26742234390504221 -> 0.66735215252994995 -0.39078997935420956 +tan0007 tan -0.87639597720371365 -55.586225523280206 -> -1.0285264565948176e-48 -1.0 +tan0008 tan -0.015783869596427243 -520.05944436039272 -> -0.0 -1.0 +tan0009 tan -0.84643549990725164 2.0749097935396343 -> -0.031412661676959573 1.0033548479526764 +tan0010 tan -0.43613792248559646 8.1082741629458059 -> -1.3879848444644593e-07 0.99999988344224011 +tan0011 tan -1.0820906367833114 0.28571868992480248 -> -1.3622485737936536 0.99089269377971245 +tan0012 tan -1.1477859580220084 1.9021637002708041 -> -0.034348450042071196 1.0293954097901687 +tan0013 tan -0.12465543176953409 3.0606851016344815e-05 -> -0.12530514290387343 3.1087420769945479e-05 +tan0014 tan 3.7582848717525343 -692787020.44038939 -> 0.0 -1.0 +tan0015 tan 2.2321967655142176e-06 -10.090069423008169 -> 1.5369846120622643e-14 -0.99999999655723759 +tan0016 tan 0.88371172390245012 -1.1635053630132823 -> 0.19705017118625889 -1.0196452280843129 +tan0017 tan 2.1347414231849267 -1.9311339960416831 -> -0.038663576915982524 -1.0174399993980778 +tan0018 tan 5.9027945255899974 -2.1574195684607135e-183 -> -0.39986591539281496 -2.5023753167976915e-183 +tan0019 tan 0.44811489490805362 683216075670.07556 -> 0.0 1.0 +tan0020 tan 4.1459766396068325 12.523017205605756 -> 2.4022514758988068e-11 1.0000000000112499 +tan0021 tan 1.7809617968443272 1.5052381702853379 -> -0.044066222118946903 1.0932684517702778 +tan0022 tan 1.1615313900880577 1.7956298728647107 -> 0.041793186826390362 1.0375339546034792 +tan0023 tan 0.067014779477908945 5.8517361577457097 -> 2.2088639754800034e-06 0.9999836182420061 + +-- Additional real values (Jython) +tan0050 tan 1e-100 0.0 -> 1.00000000000000002e-100 0.0 +tan0051 tan 3.7e-08 0.0 -> 3.7000000000000017328e-8 0.0 +tan0052 tan 0.001 0.0 -> 0.0010000003333334666875 0.0 +tan0053 tan 0.2 0.0 -> 0.20271003550867249488 0.0 +tan0054 tan 1.0 0.0 -> 1.5574077246549022305 0.0 +tan0055 tan -3.7e-08 0.0 -> -3.7000000000000017328e-8 0.0 +tan0056 tan -0.001 0.0 -> -0.0010000003333334666875 0.0 +tan0057 tan -1.0 0.0 -> -1.5574077246549022305 0.0 +tan0058 tan 0.4636476090008061 0.0 -> 0.49999999999999997163 0.0 +tan0059 tan -0.4636476090008061 0.0 -> -0.49999999999999997163 0.0 +tan0060 tan 1.1071487177940904 0.0 -> 1.9999999999999995298 0.0 +tan0061 tan -1.1071487177940904 0.0 -> -1.9999999999999995298 0.0 +tan0062 tan 1.5 0.0 -> 14.101419947171719388 0.0 +tan0063 tan 1.57 0.0 -> 1255.7655915007896475 0.0 +tan0064 tan 1.5707963267948961 0.0 -> 1978937966095219.0538 0.0 + +-- special values +tan1000 tan -0.0 0.0 -> -0.0 0.0 +tan1001 tan -inf 0.0 -> nan nan invalid +tan1002 tan -inf 2.2999999999999998 -> nan nan invalid +tan1003 tan nan 0.0 -> nan nan +tan1004 tan nan 2.2999999999999998 -> nan nan +tan1005 tan -0.0 inf -> -0.0 1.0 +tan1006 tan -0.69999999999999996 inf -> -0.0 1.0 +tan1007 tan -1.3999999999999999 inf -> -0.0 1.0 +tan1008 tan -2.1000000000000001 inf -> 0.0 1.0 +tan1009 tan -2.7999999999999998 inf -> 0.0 1.0 +tan1010 tan -3.5 inf -> -0.0 1.0 +tan1011 tan -inf inf -> -0.0 1.0 ignore-real-sign +tan1012 tan nan inf -> -0.0 1.0 ignore-real-sign +tan1013 tan -0.0 nan -> -0.0 nan +tan1014 tan -2.2999999999999998 nan -> nan nan +tan1015 tan -inf nan -> nan nan +tan1016 tan nan nan -> nan nan +tan1017 tan 0.0 0.0 -> 0.0 0.0 +tan1018 tan inf 0.0 -> nan nan invalid +tan1019 tan inf 2.2999999999999998 -> nan nan invalid +tan1020 tan 0.0 inf -> 0.0 1.0 +tan1021 tan 0.69999999999999996 inf -> 0.0 1.0 +tan1022 tan 1.3999999999999999 inf -> 0.0 1.0 +tan1023 tan 2.1000000000000001 inf -> -0.0 1.0 +tan1024 tan 2.7999999999999998 inf -> -0.0 1.0 +tan1025 tan 3.5 inf -> 0.0 1.0 +tan1026 tan inf inf -> -0.0 1.0 ignore-real-sign +tan1027 tan 0.0 nan -> 0.0 nan +tan1028 tan 2.2999999999999998 nan -> nan nan +tan1029 tan inf nan -> nan nan +tan1030 tan 0.0 -0.0 -> 0.0 -0.0 +tan1031 tan inf -0.0 -> nan nan invalid +tan1032 tan inf -2.2999999999999998 -> nan nan invalid +tan1033 tan nan -0.0 -> nan nan +tan1034 tan nan -2.2999999999999998 -> nan nan +tan1035 tan 0.0 -inf -> 0.0 -1.0 +tan1036 tan 0.69999999999999996 -inf -> 0.0 -1.0 +tan1037 tan 1.3999999999999999 -inf -> 0.0 -1.0 +tan1038 tan 2.1000000000000001 -inf -> -0.0 -1.0 +tan1039 tan 2.7999999999999998 -inf -> -0.0 -1.0 +tan1040 tan 3.5 -inf -> 0.0 -1.0 +tan1041 tan inf -inf -> -0.0 -1.0 ignore-real-sign +tan1042 tan nan -inf -> -0.0 -1.0 ignore-real-sign +tan1043 tan -0.0 -0.0 -> -0.0 -0.0 +tan1044 tan -inf -0.0 -> nan nan invalid +tan1045 tan -inf -2.2999999999999998 -> nan nan invalid +tan1046 tan -0.0 -inf -> -0.0 -1.0 +tan1047 tan -0.69999999999999996 -inf -> -0.0 -1.0 +tan1048 tan -1.3999999999999999 -inf -> -0.0 -1.0 +tan1049 tan -2.1000000000000001 -inf -> 0.0 -1.0 +tan1050 tan -2.7999999999999998 -inf -> 0.0 -1.0 +tan1051 tan -3.5 -inf -> -0.0 -1.0 +tan1052 tan -inf -inf -> -0.0 -1.0 ignore-real-sign + + +------------------------------------------------------------------------ +-- rect: Conversion from polar coordinates to rectangular coordinates -- +------------------------------------------------------------------------ +-- +-- For cmath.rect, we can use the same testcase syntax as for the +-- complex -> complex functions above, but here the input arguments +-- should be interpreted as a pair of floating-point numbers rather +-- than the real and imaginary parts of a complex number. +-- +-- Here are the 'spirit of C99' rules for rect. First, the short +-- version: +-- +-- rect(x, t) = exp(log(x)+it) for positive-signed x +-- rect(x, t) = -exp(log(-x)+it) for negative-signed x +-- rect(nan, t) = exp(nan + it), except that in rect(nan, +-0) the +-- sign of the imaginary part is unspecified. +-- +-- and now the long version: +-- +-- rect(x, -t) = conj(rect(x, t)) for all x and t +-- rect(-x, t) = -rect(x, t) for all x and t +-- rect(+0, +0) returns +0 + i0 +-- rect(+0, inf) returns +- 0 +- i0, where the signs of the real and +-- imaginary parts are unspecified. +-- rect(x, inf) returns NaN + i NaN and raises the "invalid" +-- floating-point exception, for finite nonzero x. +-- rect(inf, inf) returns +-inf + i NaN and raises the "invalid" +-- floating-point exception (where the sign of the real part of the +-- result is unspecified). +-- rect(inf, +0) returns inf+i0 +-- rect(inf, x) returns inf*cis(x), for finite nonzero x +-- rect(inf, NaN) returns +-inf+i NaN, where the sign of the real part +-- of the result is unspecified. +-- rect(NaN, x) returns NaN + i NaN for all nonzero numbers (including +-- infinities) x +-- rect(NaN, 0) returns NaN +- i0, where the sign of the imaginary +-- part is unspecified +-- rect(NaN, NaN) returns NaN + i NaN +-- rect(x, NaN) returns NaN + i NaN for finite nonzero x +-- rect(+0, NaN) return +-0 +- i0, where the signs of the real and +-- imaginary parts are unspecified. + +-- special values +rect1000 rect 0.0 0.0 -> 0.0 0.0 +rect1001 rect 0.0 inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1002 rect 2.3 inf -> nan nan invalid +rect1003 rect inf inf -> inf nan invalid ignore-real-sign +rect1004 rect inf 0.0 -> inf 0.0 +rect1005 rect inf 1.4 -> inf inf +rect1006 rect inf 2.8 -> -inf inf +rect1007 rect inf 4.2 -> -inf -inf +rect1008 rect inf 5.6 -> inf -inf +rect1009 rect inf 7.0 -> inf inf +rect1010 rect nan 0.0 -> nan 0.0 ignore-imag-sign +rect1011 rect nan 2.3 -> nan nan +rect1012 rect nan inf -> nan nan +rect1013 rect nan nan -> nan nan +rect1014 rect inf nan -> inf nan ignore-real-sign +rect1015 rect 2.3 nan -> nan nan +rect1016 rect 0.0 nan -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1017 rect 0.0 -0.0 -> 0.0 -0.0 +rect1018 rect 0.0 -inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1019 rect 2.3 -inf -> nan nan invalid +rect1020 rect inf -inf -> inf nan invalid ignore-real-sign +rect1021 rect inf -0.0 -> inf -0.0 +rect1022 rect inf -1.4 -> inf -inf +rect1023 rect inf -2.8 -> -inf -inf +rect1024 rect inf -4.2 -> -inf inf +rect1025 rect inf -5.6 -> inf inf +rect1026 rect inf -7.0 -> inf -inf +rect1027 rect nan -0.0 -> nan 0.0 ignore-imag-sign +rect1028 rect nan -2.3 -> nan nan +rect1029 rect nan -inf -> nan nan +rect1030 rect -0.0 0.0 -> -0.0 -0.0 +rect1031 rect -0.0 inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1032 rect -2.3 inf -> nan nan invalid +rect1033 rect -inf inf -> -inf nan invalid ignore-real-sign +rect1034 rect -inf 0.0 -> -inf -0.0 +rect1035 rect -inf 1.4 -> -inf -inf +rect1036 rect -inf 2.8 -> inf -inf +rect1037 rect -inf 4.2 -> inf inf +rect1038 rect -inf 5.6 -> -inf inf +rect1039 rect -inf 7.0 -> -inf -inf +rect1040 rect -inf nan -> inf nan ignore-real-sign +rect1041 rect -2.3 nan -> nan nan +rect1042 rect -0.0 nan -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1043 rect -0.0 -0.0 -> -0.0 0.0 +rect1044 rect -0.0 -inf -> 0.0 0.0 ignore-real-sign ignore-imag-sign +rect1045 rect -2.3 -inf -> nan nan invalid +rect1046 rect -inf -inf -> -inf nan invalid ignore-real-sign +rect1047 rect -inf -0.0 -> -inf 0.0 +rect1048 rect -inf -1.4 -> -inf inf +rect1049 rect -inf -2.8 -> inf inf +rect1050 rect -inf -4.2 -> inf -inf +rect1051 rect -inf -5.6 -> -inf -inf +rect1052 rect -inf -7.0 -> -inf inf + +------------------------------------------------------------------------- +-- polar: Conversion from rectangular coordinates to polar coordinates -- +------------------------------------------------------------------------- +-- +-- For cmath.polar, we can use the same testcase syntax as for the +-- complex -> complex functions above, but here the output arguments +-- should be interpreted as a pair of floating-point numbers rather +-- than the real and imaginary parts of a complex number. +-- +-- Annex G of the C99 standard describes fully both the real and +-- imaginary parts of polar (as cabs and carg, respectively, which in turn +-- are defined in terms of the functions hypot and atan2). + +-- overflow +polar0100 polar 1.4e308 1.4e308 -> inf 0.78539816339744828 overflow + +-- special values +polar1000 polar 0.0 0.0 -> 0.0 0.0 +polar1001 polar 0.0 -0.0 -> 0.0 -0.0 +polar1002 polar -0.0 0.0 -> 0.0 3.1415926535897931 +polar1003 polar -0.0 -0.0 -> 0.0 -3.1415926535897931 +polar1004 polar inf 0.0 -> inf 0.0 +polar1005 polar inf 2.3 -> inf 0.0 +polar1006 polar inf inf -> inf 0.78539816339744828 +polar1007 polar 2.3 inf -> inf 1.5707963267948966 +polar1008 polar 0.0 inf -> inf 1.5707963267948966 +polar1009 polar -0.0 inf -> inf 1.5707963267948966 +polar1010 polar -2.3 inf -> inf 1.5707963267948966 +polar1011 polar -inf inf -> inf 2.3561944901923448 +polar1012 polar -inf 2.3 -> inf 3.1415926535897931 +polar1013 polar -inf 0.0 -> inf 3.1415926535897931 +polar1014 polar -inf -0.0 -> inf -3.1415926535897931 +polar1015 polar -inf -2.3 -> inf -3.1415926535897931 +polar1016 polar -inf -inf -> inf -2.3561944901923448 +polar1017 polar -2.3 -inf -> inf -1.5707963267948966 +polar1018 polar -0.0 -inf -> inf -1.5707963267948966 +polar1019 polar 0.0 -inf -> inf -1.5707963267948966 +polar1020 polar 2.3 -inf -> inf -1.5707963267948966 +polar1021 polar inf -inf -> inf -0.78539816339744828 +polar1022 polar inf -2.3 -> inf -0.0 +polar1023 polar inf -0.0 -> inf -0.0 +polar1024 polar nan -inf -> inf nan +polar1025 polar nan -2.3 -> nan nan +polar1026 polar nan -0.0 -> nan nan +polar1027 polar nan 0.0 -> nan nan +polar1028 polar nan 2.3 -> nan nan +polar1029 polar nan inf -> inf nan +polar1030 polar nan nan -> nan nan +polar1031 polar inf nan -> inf nan +polar1032 polar 2.3 nan -> nan nan +polar1033 polar 0.0 nan -> nan nan +polar1034 polar -0.0 nan -> nan nan +polar1035 polar -2.3 nan -> nan nan +polar1036 polar -inf nan -> inf nan diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -446,11 +446,8 @@ self.assertTrue(math.isnan(abs(complex(2.3, NAN)))) self.assertEqual(abs(complex(INF, NAN)), INF) self.assertTrue(math.isnan(abs(complex(NAN, NAN)))) - if is_jython: - self.assertEqual(abs(complex(1.4e308, 1.4e308)), INF) - else: - if float.__getformat__("double").startswith("IEEE"): - self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308)) + if float.__getformat__("double").startswith("IEEE"): + self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308)) def assertCEqual(self, a, b): eps = 1E-7 diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1,7 +1,7 @@ # Python test set -- math module # XXXX Should not do tests around zero only -from test.test_support import run_unittest, verbose +from test.test_support import run_unittest, verbose, is_jython import unittest import math import os @@ -933,6 +933,7 @@ else: self.fail("sqrt(-1) didn't raise ValueError") + @unittest.skipIf(is_jython, "superseded in test_math_jy (don't fix me)") @requires_IEEE_754 def test_testfile(self): for id, fn, ar, ai, er, ei, flags in parse_testfile(test_file): diff --git a/Lib/test/test_math_jy.py b/Lib/test/test_math_jy.py --- a/Lib/test/test_math_jy.py +++ b/Lib/test/test_math_jy.py @@ -5,12 +5,23 @@ import math import unittest from test import test_support +from test.test_math import (MathTests, ulps_check, + parse_testfile, test_file) + from java.lang import Math inf = float('inf') ninf = float('-inf') nan = float('nan') +# Optional tests use mpmath +try: + import mpmath + HAVE_MPMATH = True +except: + HAVE_MPMATH = False + + class MathTestCase(unittest.TestCase): def test_frexp(self): @@ -40,28 +51,104 @@ self.assertRaises(ValueError, math.log, -1.5) self.assertRaises(ValueError, math.log, -0.5) -from test.test_math import MathTests class MathAccuracy(MathTests): # Run the CPython tests but expect accurate results - def ftest(self, name, value, expected): + def ftest(self, name, value, expected, ulps_err=1): + if expected != 0. : # Tolerate small deviation in proportion to expected - tol = Math.ulp(expected) + ulp_unit = Math.ulp(expected) else : # On zero, allow 2**-52. Maybe allow different slack based on name - tol = Math.ulp(1.) + ulp_unit = Math.ulp(1.) - if abs(value-expected) > tol: + # Complex expressions accumulate errors + if name in ('cosh(2)-2*cosh(1)**2', 'sinh(1)**2-cosh(1)**2') : + # ... quite steeply in these cases + ulps_err *= 5 + + err = value-expected + + if abs(err) > ulps_err * ulp_unit: # Use %r to display full precision. - message = '%s returned %r, expected %r' % (name, value, expected) + message = '%s returned %r, expected %r (%r ulps)' % \ + (name, value, expected, round(err/ulp_unit, 1)) self.fail(message) def testConstants(self): - self.ftest('pi', math.pi, Math.PI) # 3.141592653589793238462643 - self.ftest('e', math.e, Math.E) # 2.718281828459045235360287 + # Override MathTests.testConstants requiring equality with java.Math + self.assertEqual(math.pi, Math.PI) + self.assertEqual(math.e, Math.E) + def test_testfile(self, math_module=math, ulps_err=None): + # Rigorous variant of MathTests.test_testfile requiring accuracy in ulps. + fail_fmt = "{}:{}({!r}): expected {!r}, got {!r}" + failures = [] + + for id, fn, ar, ai, er, ei, flags in parse_testfile(test_file): + # Skip if either the input or result is complex, or if + # flags is nonempty + if ai != 0. or ei != 0. or flags: + continue + if fn in ['rect', 'polar']: + # no real versions of rect, polar + continue + + if ulps_err is not None : + fn_ulps_err = ulps_err + else : + # java.Math mostly promises 1 ulp, except for: + if fn in ['atan2'] : + fn_ulps_err = 2 + elif fn in ['cosh', 'sinh', 'tanh'] : + fn_ulps_err = 2.5 + else : + fn_ulps_err = 1 + + func = getattr(math_module, fn) + arg = ar + expected = er + + if 'invalid' in flags or 'divide-by-zero' in flags: + expected = 'ValueError' + elif 'overflow' in flags: + expected = 'OverflowError' + + try: + got = float(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 + accuracy_failure = ulps_check(expected, got, fn_ulps_err) + 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) + + if failures: + self.fail('Failures in test_testfile:\n ' + + '\n '.join(failures)) + + @unittest.skipUnless(HAVE_MPMATH, "requires mpmath module") + def test_testfile_mpmath(self): + # Run the mpmath module on the same material: consistency check during development. + with mpmath.workprec(100) : + self.test_testfile(mpmath, 1, 1) def test_main(): diff --git a/Misc/make_cmath_testcases.py b/Misc/make_cmath_testcases.py new file mode 100644 --- /dev/null +++ b/Misc/make_cmath_testcases.py @@ -0,0 +1,124 @@ +# This work is based on test_math.py in the Python test set. +# It a provides a tool to generate additional real test cases. + +import math +import mpmath + + +# Table of additional real test cases. The layout is +# +# function : ( starting_number [ x1, x2, x3, ... ] ), +# +# Where tests will be numbered functionNNNN and each xn +# generates a new test with (complex) argument xn + 0j. + +cases_to_generate = { + + 'atan' : ( 400, [ + float.fromhex('0x1.fffffffffffffp1023'), + float.fromhex('-0x1.fffffffffffffp1023'), + 1e-17, -1e-17, 1e-4, -1e-4, + 1 - 1e-15, 1 + 1e-15, + 14.101419947171719, # tan(1.5) + 1255.7655915007896, # tan(1.57) + ]), + + 'cos' : ( 50, [ + 1e-150, 1e-18, 1e-9, 0.0003, 0.2, 1.0, + -1e-18, -0.0003, -1.0, + 1.0471975511965977, # -> 0.5 + 2.5707963267948966, + -2.5707963267948966, + 18, 18.0 + ]), + + 'cosh' : ( 50, [ + 1e-150, 1e-18, 1e-9, 0.0003, 0.2, 1.0, + -1e-18, -0.0003, -1.0, + 1.3169578969248167086, # -> 2. + -1.3169578969248167086, + 25*math.log(2), # cosh != exp at 52 bits + 27*math.log(2), # cosh == exp at 52 bits + 709.7827, # not quite overflow + -709.7827, # not quite overflow + ]), + + 'exp' : ( 70, [ + 1e-8, 0.0003, 0.2, 1.0, + -1e-8, -0.0003, -1.0, + 2**-52, -2**-53, # exp != 1 (just) + 2.3025850929940457, # -> 10 + -2.3025850929940457, + 709.7827, # not quite overflow + ]), + + 'sin' : ( 50, [ + 1e-100, 3.7e-8, 0.001, 0.2, 1.0, + -3.7e-8, -0.001, -1.0, + 0.5235987755982989, # -> 0.5 + -0.5235987755982989, + 2.617993877991494365, + -2.617993877991494365, + ]), + + 'sinh' : ( 50, [ + 1e-100, 5e-17, 1e-16, 3.7e-8, 0.001, 0.2, 1.0, + -3.7e-8, -0.001, -1.0, + 1.44363547517881034, # -> 2. + -1.44363547517881034, + 25*math.log(2), # sinh != exp at 52 bits + 27*math.log(2), # sinh == exp at 52 bits + 709.7827, # not quite overflow + -709.7827, # not quite overflow + ]), + + 'tan' : ( 50, [ + 1e-100, 3.7e-8, 0.001, 0.2, 1.0, + -3.7e-8, -0.001, -1.0, + 0.463647609000806116, # -> 0.5 + -0.463647609000806116, + 1.1071487177940905, # -> 0.5 + -1.1071487177940905, + 1.5, + 1.57, + math.pi/2 - 2**-51, + ]), + + 'tanh' : ( 50, [ + 1e-100, 5e-17, 1e-16, 3.7e-8, 0.001, 0.2, 1.0, + -3.7e-8, -0.001, -1.0, + 0.54930614433405484, # -> 0.5 + -0.54930614433405484, + 25*math.log(2), # sinh != cosh at 52 bits + 27*math.log(2), # sinh == cosh at 52 bits + 711, # oveflow cosh in naive impl + 1.797e+308, # risk overflow + ]), + + 'sqrt' : ( 150, [ + float.fromhex('0x1.fffffffffffffp1023'), + float.fromhex('0x1.0p-1022'), + float.fromhex('0x0.0000000000001p-1022'), + ]), + } + +def generate_cases() : + fmt = "{}{:04d} {} {!r} 0.0 -> {} 0.0" + for fn in sorted(cases_to_generate.keys()): + print "-- Additional real values (Jython)" + count, xlist = cases_to_generate[fn] + for x in xlist: + func = getattr(mpmath, fn) + y = func(x) + print fmt.format(fn, count, fn, x, mpmath.nstr(y, 20) ) + count += 1 + +def test_main(): + with mpmath.workprec(100): + generate_cases() + +if __name__ == '__main__': + test_main() + + # Conveniences for interactive use + from mpmath import mp, mpf, workprec, workdps, nstr diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java --- a/src/org/python/modules/math.java +++ b/src/org/python/modules/math.java @@ -20,7 +20,6 @@ private static final double ZERO = 0.0; private static final double MINUS_ZERO = -0.0; - private static final double HALF = 0.5; private static final double ONE = 1.0; private static final double MINUS_ONE = -1.0; private static final double TWO = 2.0; @@ -67,13 +66,7 @@ } public static double acos(double v) { - if (isinf(v)) { - throwMathDomainValueError(); - } - if (isnan(v)) { - return v; - } - return Math.acos(v); + return exceptNaN(Math.acos(v), v); } /** @@ -108,13 +101,7 @@ } public static double asin(double v) { - if (isinf(v)) { - throwMathDomainValueError(); - } - if (isnan(v)) { - return v; - } - return Math.asin(v); + return exceptNaN(Math.asin(v), v); } public static double asinh(double v) { @@ -147,17 +134,14 @@ } public static double atan(double v) { - if (isnan(v)) { - return v; - } - return Math.atan(v); + return exceptNaN(Math.atan(v), v); } /** * Compute tanh-1y. * * @param y - * @return x such that tanh x = y + * @return x such that tanh x = y */ public static double atanh(double y) { double absy = Math.abs(y); @@ -180,40 +164,19 @@ } public static double ceil(double v) { - if (isnan(v) || isinf(v)) { - return v; - } return Math.ceil(v); } public static double cos(double v) { - if (isinf(v)) { - throwMathDomainValueError(); - } - if (isnan(v)) { - return NAN; - } - return Math.cos(v); + return exceptNaN(Math.cos(v), v); } public static double cosh(double v) { - if (isinf(v)) { - return INF; - } - if (isnan(v)) { - return v; - } - return HALF * (Math.exp(v) + Math.exp(-v)); + return exceptInf(Math.cosh(v), v); } public static double exp(double v) { - if (isninf(v)) { - return ZERO; - } - if (isnan(v) || isinf(v)) { - return v; - } - return check(Math.exp(v)); + return exceptInf(Math.exp(v), v); } public static double floor(PyObject v) { @@ -221,9 +184,6 @@ } public static double floor(double v) { - if (isnan(v) || isinf(v)) { - return v; - } return Math.floor(v); } @@ -238,10 +198,7 @@ } else { doubleValue = log(v.asDouble()); } - if (base != null) { - return check(applyLoggedBase(doubleValue, base)); - } - return doubleValue; + return (base == null) ? doubleValue : applyLoggedBase(doubleValue, base); } public static double pow(double v, double w) { @@ -260,7 +217,7 @@ } else if (w > ZERO || ispinf(w)) { return ZERO; } else { - throwMathDomainValueError(); + throw mathDomainError(); } } if (isninf(v)) { @@ -307,7 +264,7 @@ } } if (v < ZERO && !isIntegral(w)) { - throwMathDomainValueError(); + throw mathDomainError(); } return Math.pow(v, w); } @@ -317,13 +274,7 @@ } public static double sin(double v) { - if (isinf(v)) { - throwMathDomainValueError(); - } - if (isnan(v)) { - return v; - } - return Math.sin(v); + return exceptNaN(Math.sin(v), v); } public static double sqrt(PyObject v) { @@ -331,26 +282,11 @@ } public static double sqrt(double v) { - if (isnan(v)) { - return v; - } - if (ispinf(v)) { - return v; - } - if (isninf(v) || v < MINUS_ZERO) { - throwMathDomainValueError(); - } - return Math.sqrt(v); + return exceptNaN(Math.sqrt(v), v); } public static double tan(double v) { - if (isnan(v)) { - return NAN; - } - if (isinf(v)) { - throw Py.ValueError("math domain error"); - } - return Math.tan(v); + return exceptNaN(Math.tan(v), v); } public static double log10(PyObject v) { @@ -358,7 +294,7 @@ int exp[] = new int[1]; double x = ((PyLong)v).scaledDoubleValue(exp); if (x <= ZERO) { - throwMathDomainValueError(); + throw mathDomainError(); } return log10(x) + (exp[0] * EIGHT) * log10(TWO); } @@ -366,29 +302,11 @@ } public static double sinh(double v) { - if (isnan(v)) { - return v; - } - if (isinf(v)) { - return v; - } - return HALF * (Math.exp(v) - Math.exp(-v)); + return exceptInf(Math.sinh(v), v); } public static double tanh(double v) { - if (isnan(v)) { - return v; - } - if (isinf(v)) { - if (isninf(v)) { - return MINUS_ONE; - } - return ONE; - } - if (v == MINUS_ZERO) { - return v; - } - return sinh(v) / cosh(v); + return exceptInf(Math.tanh(v), v); } public static double fabs(double v) { @@ -403,10 +321,10 @@ return v; } if (w == ZERO) { - throwMathDomainValueError(); + throw mathDomainError(); } if (isinf(v) && w == ONE) { - throwMathDomainValueError(); + throw mathDomainError(); } return v % w; } @@ -428,25 +346,36 @@ } public static PyTuple frexp(double x) { - int exponent = 0; + int exponent; + double mantissa; - if (isnan(x) || isinf(x) || x == ZERO) { - exponent = 0; - } else { - short sign = 1; + switch (exponent = Math.getExponent(x)) { - if (x < ZERO) { - x = -x; - sign = -1; - } + default: + // x = m * 2**exponent and 1 <=abs(m) <2 + exponent = exponent + 1; + // x = m * 2**exponent and 0.5 <=abs(m) <1 + mantissa = Math.scalb(x, -exponent); + break; - for (; x < HALF; x *= TWO, exponent--) {} + case 1024: // nan or inf + mantissa = x; + exponent = 0; + break; - for (; x >= ONE; x *= HALF, exponent++) {} + case -1023: + if (x == 0.) { // , 0.0 or -0.0 + mantissa = x; + exponent = 0; + } else { // denormalised value + // x = m * 2**exponent but 0 < abs(m) < 1 + exponent = Math.getExponent(x * 0x1p52) - 51; + mantissa = Math.scalb(x, -exponent); + } + break; + } - x *= sign; - } - return new PyTuple(new PyFloat(x), new PyInteger(exponent)); + return new PyTuple(new PyFloat(mantissa), new PyInteger(exponent)); } public static PyObject trunc(PyObject number) { @@ -454,23 +383,13 @@ } public static double ldexp(double v, PyObject wObj) { - if (ZERO == v) { - return v; // can be negative zero + long w = getLong(wObj); + if (w < Integer.MIN_VALUE) { + w = Integer.MIN_VALUE; + } else if (w > Integer.MAX_VALUE) { + w = Integer.MAX_VALUE; } - if (isinf(v)) { - return v; - } - if (isnan(v)) { - return v; - } - long w = getLong(wObj); - if (w == Long.MIN_VALUE) { - if (v > ZERO) { - return ZERO; - } - return MINUS_ZERO; - } - return checkOverflow(v * Math.pow(TWO, w)); + return exceptInf(Math.scalb(v, (int)w), v); } /** @@ -492,11 +411,12 @@ } public static double radians(double v) { - return check(Math.toRadians(v)); + return Math.toRadians(v); } public static double degrees(double v) { - return check(Math.toDegrees(v)); + // Note that this does not raise overflow in Python: 1e307 -> inf as in Java. + return Math.toDegrees(v); } public static boolean isnan(double v) { @@ -513,36 +433,33 @@ } public static double copysign(double v, double w) { - if (isnan(v)) { - return NAN; - } - if (signum(v) == signum(w)) { - return v; - } - return v *= MINUS_ONE; + return Math.copySign(v, w); } public static PyLong factorial(double v) { if (v == ZERO || v == ONE) { return new PyLong(1); + } else if (v < ZERO || isnan(v) || isinf(v)) { + throw mathDomainError(); + } else if (!isIntegral(v)) { + throw mathDomainError(); + } else { + // long input should be big enough :-) + long value = (long)v; + BigInteger bi = new BigInteger(Long.toString(value)); + for (long l = value - 1; l > 1; l--) { + bi = bi.multiply(new BigInteger(Long.toString(l))); + } + return new PyLong(bi); } - if (v < ZERO || isnan(v) || isinf(v)) { - throwMathDomainValueError(); - } - if (!isIntegral(v)) { - throwMathDomainValueError(); - } - // long input should be big enough :-) - long value = (long)v; - BigInteger bi = new BigInteger(Long.toString(value)); - for (long l = value - 1; l > 1; l--) { - bi = bi.multiply(new BigInteger(Long.toString(l))); - } - return new PyLong(bi); } public static double log1p(double v) { - return log(ONE + v); + if (v <= -1.) { + throw mathDomainError(); + } else { + return Math.log1p(v); + } } public static double fsum(final PyObject iterable) { @@ -554,7 +471,7 @@ int exp[] = new int[1]; double x = v.scaledDoubleValue(exp); if (x <= ZERO) { - throwMathDomainValueError(); + throw mathDomainError(); } return log(x) + (exp[0] * EIGHT) * log(TWO); } @@ -566,27 +483,23 @@ } else { loggedBase = log(base.asDouble()); } - return check(loggedValue / loggedBase); + return loggedValue / loggedBase; } private static double log(double v) { - if (isninf(v) || v <= ZERO) { - throwMathDomainValueError(); + if (v <= 0.) { + throw mathDomainError(); + } else { + return Math.log(v); } - if (isinf(v) || isnan(v)) { - return v; - } - return Math.log(v); } private static double log10(double v) { - if (isninf(v)) { - throwMathDomainValueError(); + if (v <= 0.) { + throw mathDomainError(); + } else { + return Math.log10(v); } - if (isinf(v) || isnan(v)) { - return v; - } - return Math.log10(v); } private static boolean isninf(double v) { @@ -598,21 +511,6 @@ } /** - * work around special Math.signum() behaviour for positive and negative zero - */ - private static double signum(double v) { - double signum = ONE; - if (v == ZERO) { - if ('-' == Double.toString(v).charAt(0)) { - signum = MINUS_ONE; - } - } else { - signum = Math.signum(v); - } - return signum; - } - - /** * Returns a ValueError("math domain error"), ready to throw from the client code. * * @return ValueError("math domain error") @@ -630,25 +528,57 @@ return Py.OverflowError("math range error"); } - private static void throwMathDomainValueError() { - throw Py.ValueError("math domain error"); + /** + * Turn a NaN result into a thrown ValueError, a math domain error, if + * the original argument was not itself NaN. Use as: + * + *
+     * public static double asin(double v) { return exceptNaN(Math.asin(v), v); }
+     * 
+ * + * Note that the original function argument is also supplied to this method. Most Java math + * library methods do exactly what we need for Python, but some return {@value Double#NaN} when + * Python should raise ValueError. This is a brief way to change that. + * + * @param result to return (if we return) + * @param arg to include in check + * @return result if arg was NaN or result was not + * NaN + * @throws PyException (ValueError) if result was NaN and + * arg was not NaN + */ + private static double exceptNaN(double result, double arg) throws PyException { + if (Double.isNaN(result) && !Double.isNaN(arg)) { + throw mathDomainError(); + } else { + return result; + } } - private static double check(double v) { - if (isnan(v)) { - throwMathDomainValueError(); + /** + * Turn an infinite result into a thrown OverflowError, a math range error, if the + * original argument was not itself infinite. Use as: + * + *
+     * public static double cosh(double v) { return exceptInf( Math.cosh(v), v); }
+     * 
+ * + * Note that the original function argument is also supplied to this method. Most Java math + * library methods do exactly what we need for Python, but some return an infinity when Python + * should raise OverflowError. This is a brief way to change that. + * + * @param result to return (if we return) + * @param arg to include in check + * @return result if arg was infinite or result was not infinite + * @throws PyException (ValueError) if result was infinite and arg was + * not infinite + */ + private static double exceptInf(double result, double arg) { + if (Double.isInfinite(result) && !Double.isInfinite(arg)) { + throw Py.OverflowError("math range error"); + } else { + return result; } - if (isinf(v)) { - throw Py.OverflowError("math range error"); - } - return v; - } - - private static double checkOverflow(double v) { - if (isinf(v)) { - throw Py.OverflowError("math range error"); - } - return v; } /** -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 20:23:01 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 06 Jan 2015 19:23:01 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Use_Java_equivalents_of_fre?= =?utf-8?q?xp=2C_ldexp_and_copysign_directly=2E?= Message-ID: <20150106192300.11573.16181@psf.io> https://hg.python.org/jython/rev/44cfecd93257 changeset: 7510:44cfecd93257 user: Jeff Allen date: Mon Jan 05 23:17:51 2015 +0000 summary: Use Java equivalents of frexp, ldexp and copysign directly. files: src/org/python/modules/math.java | 92 ++++++------------- 1 files changed, 32 insertions(+), 60 deletions(-) diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java --- a/src/org/python/modules/math.java +++ b/src/org/python/modules/math.java @@ -20,7 +20,6 @@ private static final double ZERO = 0.0; private static final double MINUS_ZERO = -0.0; - private static final double HALF = 0.5; private static final double ONE = 1.0; private static final double MINUS_ONE = -1.0; private static final double TWO = 2.0; @@ -347,25 +346,36 @@ } public static PyTuple frexp(double x) { - int exponent = 0; + int exponent; + double mantissa; - if (isnan(x) || isinf(x) || x == ZERO) { - exponent = 0; - } else { - short sign = 1; + switch (exponent = Math.getExponent(x)) { - if (x < ZERO) { - x = -x; - sign = -1; - } + default: + // x = m * 2**exponent and 1 <=abs(m) <2 + exponent = exponent + 1; + // x = m * 2**exponent and 0.5 <=abs(m) <1 + mantissa = Math.scalb(x, -exponent); + break; - for (; x < HALF; x *= TWO, exponent--) {} + case 1024: // nan or inf + mantissa = x; + exponent = 0; + break; - for (; x >= ONE; x *= HALF, exponent++) {} + case -1023: + if (x == 0.) { // , 0.0 or -0.0 + mantissa = x; + exponent = 0; + } else { // denormalised value + // x = m * 2**exponent but 0 < abs(m) < 1 + exponent = Math.getExponent(x * 0x1p52) - 51; + mantissa = Math.scalb(x, -exponent); + } + break; + } - x *= sign; - } - return new PyTuple(new PyFloat(x), new PyInteger(exponent)); + return new PyTuple(new PyFloat(mantissa), new PyInteger(exponent)); } public static PyObject trunc(PyObject number) { @@ -373,23 +383,13 @@ } public static double ldexp(double v, PyObject wObj) { - if (ZERO == v) { - return v; // can be negative zero + long w = getLong(wObj); + if (w < Integer.MIN_VALUE) { + w = Integer.MIN_VALUE; + } else if (w > Integer.MAX_VALUE) { + w = Integer.MAX_VALUE; } - if (isinf(v)) { - return v; - } - if (isnan(v)) { - return v; - } - long w = getLong(wObj); - if (w == Long.MIN_VALUE) { - if (v > ZERO) { - return ZERO; - } - return MINUS_ZERO; - } - return checkOverflow(v * Math.pow(TWO, w)); + return exceptInf(Math.scalb(v, (int)w), v); } /** @@ -433,13 +433,7 @@ } public static double copysign(double v, double w) { - if (isnan(v)) { - return NAN; - } - if (signum(v) == signum(w)) { - return v; - } - return v *= MINUS_ONE; + return Math.copySign(v, w); } public static PyLong factorial(double v) { @@ -517,21 +511,6 @@ } /** - * work around special Math.signum() behaviour for positive and negative zero - */ - private static double signum(double v) { - double signum = ONE; - if (v == ZERO) { - if ('-' == Double.toString(v).charAt(0)) { - signum = MINUS_ONE; - } - } else { - signum = Math.signum(v); - } - return signum; - } - - /** * Returns a ValueError("math domain error"), ready to throw from the client code. * * @return ValueError("math domain error") @@ -549,13 +528,6 @@ return Py.OverflowError("math range error"); } - private static double checkOverflow(double v) { - if (isinf(v)) { - throw Py.OverflowError("math range error"); - } - return v; - } - /** * Turn a NaN result into a thrown ValueError, a math domain error, if * the original argument was not itself NaN. Use as: -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 20:23:01 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 06 Jan 2015 19:23:01 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Remove_checks_from_math_whe?= =?utf-8?q?re_java=2Elang=2EMath_suffices=2E?= Message-ID: <20150106192259.22405.97985@psf.io> https://hg.python.org/jython/rev/dbfba99fe271 changeset: 7509:dbfba99fe271 user: Jeff Allen date: Mon Jan 05 21:12:54 2015 +0000 summary: Remove checks from math where java.lang.Math suffices. java.lang.Math often does the right thing for Python, and never raises. In some cases we need to convert a nan or inf returned, into a Python domain or range error. files: src/org/python/modules/math.java | 214 ++++++++---------- 1 files changed, 98 insertions(+), 116 deletions(-) diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java --- a/src/org/python/modules/math.java +++ b/src/org/python/modules/math.java @@ -67,13 +67,7 @@ } public static double acos(double v) { - if (isinf(v)) { - throwMathDomainValueError(); - } - if (isnan(v)) { - return v; - } - return Math.acos(v); + return exceptNaN(Math.acos(v), v); } /** @@ -108,13 +102,7 @@ } public static double asin(double v) { - if (isinf(v)) { - throwMathDomainValueError(); - } - if (isnan(v)) { - return v; - } - return Math.asin(v); + return exceptNaN(Math.asin(v), v); } public static double asinh(double v) { @@ -147,17 +135,14 @@ } public static double atan(double v) { - if (isnan(v)) { - return v; - } - return Math.atan(v); + return exceptNaN(Math.atan(v), v); } /** * Compute tanh-1y. * * @param y - * @return x such that tanh x = y + * @return x such that tanh x = y */ public static double atanh(double y) { double absy = Math.abs(y); @@ -180,34 +165,19 @@ } public static double ceil(double v) { - if (isnan(v) || isinf(v)) { - return v; - } return Math.ceil(v); } public static double cos(double v) { - if (isinf(v)) { - throwMathDomainValueError(); - } - if (isnan(v)) { - return NAN; - } - return Math.cos(v); + return exceptNaN(Math.cos(v), v); } public static double cosh(double v) { - return Math.cosh(v); + return exceptInf(Math.cosh(v), v); } public static double exp(double v) { - if (isninf(v)) { - return ZERO; - } - if (isnan(v) || isinf(v)) { - return v; - } - return check(Math.exp(v)); + return exceptInf(Math.exp(v), v); } public static double floor(PyObject v) { @@ -215,9 +185,6 @@ } public static double floor(double v) { - if (isnan(v) || isinf(v)) { - return v; - } return Math.floor(v); } @@ -232,10 +199,7 @@ } else { doubleValue = log(v.asDouble()); } - if (base != null) { - return check(applyLoggedBase(doubleValue, base)); - } - return doubleValue; + return (base == null) ? doubleValue : applyLoggedBase(doubleValue, base); } public static double pow(double v, double w) { @@ -254,7 +218,7 @@ } else if (w > ZERO || ispinf(w)) { return ZERO; } else { - throwMathDomainValueError(); + throw mathDomainError(); } } if (isninf(v)) { @@ -301,7 +265,7 @@ } } if (v < ZERO && !isIntegral(w)) { - throwMathDomainValueError(); + throw mathDomainError(); } return Math.pow(v, w); } @@ -311,13 +275,7 @@ } public static double sin(double v) { - if (isinf(v)) { - throwMathDomainValueError(); - } - if (isnan(v)) { - return v; - } - return Math.sin(v); + return exceptNaN(Math.sin(v), v); } public static double sqrt(PyObject v) { @@ -325,26 +283,11 @@ } public static double sqrt(double v) { - if (isnan(v)) { - return v; - } - if (ispinf(v)) { - return v; - } - if (isninf(v) || v < MINUS_ZERO) { - throwMathDomainValueError(); - } - return Math.sqrt(v); + return exceptNaN(Math.sqrt(v), v); } public static double tan(double v) { - if (isnan(v)) { - return NAN; - } - if (isinf(v)) { - throw Py.ValueError("math domain error"); - } - return Math.tan(v); + return exceptNaN(Math.tan(v), v); } public static double log10(PyObject v) { @@ -352,7 +295,7 @@ int exp[] = new int[1]; double x = ((PyLong)v).scaledDoubleValue(exp); if (x <= ZERO) { - throwMathDomainValueError(); + throw mathDomainError(); } return log10(x) + (exp[0] * EIGHT) * log10(TWO); } @@ -360,11 +303,11 @@ } public static double sinh(double v) { - return Math.sinh(v); + return exceptInf(Math.sinh(v), v); } public static double tanh(double v) { - return Math.tanh(v); + return exceptInf(Math.tanh(v), v); } public static double fabs(double v) { @@ -379,10 +322,10 @@ return v; } if (w == ZERO) { - throwMathDomainValueError(); + throw mathDomainError(); } if (isinf(v) && w == ONE) { - throwMathDomainValueError(); + throw mathDomainError(); } return v % w; } @@ -468,11 +411,12 @@ } public static double radians(double v) { - return check(Math.toRadians(v)); + return Math.toRadians(v); } public static double degrees(double v) { - return check(Math.toDegrees(v)); + // Note that this does not raise overflow in Python: 1e307 -> inf as in Java. + return Math.toDegrees(v); } public static boolean isnan(double v) { @@ -501,24 +445,27 @@ public static PyLong factorial(double v) { if (v == ZERO || v == ONE) { return new PyLong(1); + } else if (v < ZERO || isnan(v) || isinf(v)) { + throw mathDomainError(); + } else if (!isIntegral(v)) { + throw mathDomainError(); + } else { + // long input should be big enough :-) + long value = (long)v; + BigInteger bi = new BigInteger(Long.toString(value)); + for (long l = value - 1; l > 1; l--) { + bi = bi.multiply(new BigInteger(Long.toString(l))); + } + return new PyLong(bi); } - if (v < ZERO || isnan(v) || isinf(v)) { - throwMathDomainValueError(); - } - if (!isIntegral(v)) { - throwMathDomainValueError(); - } - // long input should be big enough :-) - long value = (long)v; - BigInteger bi = new BigInteger(Long.toString(value)); - for (long l = value - 1; l > 1; l--) { - bi = bi.multiply(new BigInteger(Long.toString(l))); - } - return new PyLong(bi); } public static double log1p(double v) { - return log(ONE + v); + if (v <= -1.) { + throw mathDomainError(); + } else { + return Math.log1p(v); + } } public static double fsum(final PyObject iterable) { @@ -530,7 +477,7 @@ int exp[] = new int[1]; double x = v.scaledDoubleValue(exp); if (x <= ZERO) { - throwMathDomainValueError(); + throw mathDomainError(); } return log(x) + (exp[0] * EIGHT) * log(TWO); } @@ -542,27 +489,23 @@ } else { loggedBase = log(base.asDouble()); } - return check(loggedValue / loggedBase); + return loggedValue / loggedBase; } private static double log(double v) { - if (isninf(v) || v <= ZERO) { - throwMathDomainValueError(); + if (v <= 0.) { + throw mathDomainError(); + } else { + return Math.log(v); } - if (isinf(v) || isnan(v)) { - return v; - } - return Math.log(v); } private static double log10(double v) { - if (isninf(v)) { - throwMathDomainValueError(); + if (v <= 0.) { + throw mathDomainError(); + } else { + return Math.log10(v); } - if (isinf(v) || isnan(v)) { - return v; - } - return Math.log10(v); } private static boolean isninf(double v) { @@ -606,25 +549,64 @@ return Py.OverflowError("math range error"); } - private static void throwMathDomainValueError() { - throw Py.ValueError("math domain error"); - } - - private static double check(double v) { - if (isnan(v)) { - throwMathDomainValueError(); - } + private static double checkOverflow(double v) { if (isinf(v)) { throw Py.OverflowError("math range error"); } return v; } - private static double checkOverflow(double v) { - if (isinf(v)) { + /** + * Turn a NaN result into a thrown ValueError, a math domain error, if + * the original argument was not itself NaN. Use as: + * + *
+     * public static double asin(double v) { return exceptNaN(Math.asin(v), v); }
+     * 
+ * + * Note that the original function argument is also supplied to this method. Most Java math + * library methods do exactly what we need for Python, but some return {@value Double#NaN} when + * Python should raise ValueError. This is a brief way to change that. + * + * @param result to return (if we return) + * @param arg to include in check + * @return result if arg was NaN or result was not + * NaN + * @throws PyException (ValueError) if result was NaN and + * arg was not NaN + */ + private static double exceptNaN(double result, double arg) throws PyException { + if (Double.isNaN(result) && !Double.isNaN(arg)) { + throw mathDomainError(); + } else { + return result; + } + } + + /** + * Turn an infinite result into a thrown OverflowError, a math range error, if the + * original argument was not itself infinite. Use as: + * + *
+     * public static double cosh(double v) { return exceptInf( Math.cosh(v), v); }
+     * 
+ * + * Note that the original function argument is also supplied to this method. Most Java math + * library methods do exactly what we need for Python, but some return an infinity when Python + * should raise OverflowError. This is a brief way to change that. + * + * @param result to return (if we return) + * @param arg to include in check + * @return result if arg was infinite or result was not infinite + * @throws PyException (ValueError) if result was infinite and arg was + * not infinite + */ + private static double exceptInf(double result, double arg) { + if (Double.isInfinite(result) && !Double.isInfinite(arg)) { throw Py.OverflowError("math range error"); + } else { + return result; } - return v; } /** -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 22:10:13 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Tue, 06 Jan 2015 21:10:13 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_=232236=3A_Interactive_pars?= =?utf-8?q?er_does_not_accept_try_=2E=2E=2E_except_E_as_e=3A_syntax=2E?= Message-ID: <20150106211002.125886.11415@psf.io> https://hg.python.org/jython/rev/8f083cde280f changeset: 7512:8f083cde280f user: Frank Wierzbicki date: Tue Jan 06 21:09:55 2015 +0000 summary: #2236: Interactive parser does not accept try ... except E as e: syntax. files: NEWS | 1 + grammar/PythonPartial.g | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ Jython 2.7b4 Bugs Fixed + - [ 2236 ] Interactive parser does not accept try ... except E as e: syntax - [ 2037 ] Byte-string containing elements greater than 255 Jython 2.7b3 diff --git a/grammar/PythonPartial.g b/grammar/PythonPartial.g --- a/grammar/PythonPartial.g +++ b/grammar/PythonPartial.g @@ -537,9 +537,9 @@ : (AS | NAME) expr ; -//except_clause: 'except' [test [',' test]] +//except_clause: 'except' [test [('as' | ',') test]] except_clause - : EXCEPT (test (COMMA test)?)? COLON suite + : EXCEPT (test ((COMMA | AS) test)?)? COLON suite ; //suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 6 23:52:43 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 06 Jan 2015 22:52:43 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Visit_class_decorators_when?= =?utf-8?q?_visiting_class_def_in_scopes_compilation?= Message-ID: <20150106225212.72561.81884@psf.io> https://hg.python.org/jython/rev/56b94dc065ff changeset: 7513:56b94dc065ff user: Jim Baker date: Tue Jan 06 15:52:00 2015 -0700 summary: Visit class decorators when visiting class def in scopes compilation Fixes http://bugs.jython.org/issue2232 files: Lib/test/test_decorators_jy.py | 34 ++++++++++ src/org/python/compiler/ScopesCompiler.java | 4 + 2 files changed, 38 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_decorators_jy.py b/Lib/test/test_decorators_jy.py --- a/Lib/test/test_decorators_jy.py +++ b/Lib/test/test_decorators_jy.py @@ -5,6 +5,21 @@ from test import test_support import unittest + +def funcattrs(**kwds): + def decorate(func): + func.__dict__.update(kwds) + return func + return decorate + +def classattrs(**kwds): + def decorate(cls): + for k, v in kwds.iteritems(): + setattr(cls, k, v) + return cls + return decorate + + class TestDecorators(unittest.TestCase): def test_lookup_order(self): @@ -15,6 +30,25 @@ return self.foo self.assertEqual(Foo().property, 'bar') + def test_lambda_in_class_decorator(self): + # Tests fix for http://bugs.jython.org/issue2232 + @classattrs(abc=42, xyz=lambda self: 47) + class C(object): + pass + + c = C() + self.assertEqual(c.abc, 42) + self.assertEqual(c.xyz(), 47) + + def test_lambda_in_function_decorator(self): + class C(object): + @funcattrs(abc=1, xyz=lambda: 47) + def foo(self): return 42 + + self.assertEqual(C().foo(), 42) + self.assertEqual(C().foo.abc, 1) + self.assertEqual(C().foo.xyz(), 47) + def test_main(): test_support.run_unittest(TestDecorators) diff --git a/src/org/python/compiler/ScopesCompiler.java b/src/org/python/compiler/ScopesCompiler.java --- a/src/org/python/compiler/ScopesCompiler.java +++ b/src/org/python/compiler/ScopesCompiler.java @@ -251,6 +251,10 @@ @Override public Object visitClassDef(ClassDef node) throws Exception { + List decs = node.getInternalDecorator_list(); + for (int i = decs.size() - 1; i >= 0; i--) { + visit(decs.get(i)); + } def(node.getInternalName()); int n = node.getInternalBases().size(); for (int i = 0; i < n; i++) { -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 7 00:49:15 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 06 Jan 2015 23:49:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_dict=2Epop_should_not_add_a?= =?utf-8?q?dditional_quoting_in_KeyError?= Message-ID: <20150106234911.8741.83447@psf.io> https://hg.python.org/jython/rev/82eea9aced6b changeset: 7514:82eea9aced6b user: Jim Baker date: Tue Jan 06 16:40:33 2015 -0700 summary: dict.pop should not add additional quoting in KeyError Fixes http://bugs.jython.org/issue2247 files: Lib/test/test_dict_jy.py | 18 ++++++++++++++- src/org/python/core/PyDictionary.java | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_dict_jy.py b/Lib/test/test_dict_jy.py --- a/Lib/test/test_dict_jy.py +++ b/Lib/test/test_dict_jy.py @@ -86,6 +86,16 @@ self.assertEqual(derived_dict_with_custom_cmp(), '') self.assertEqual(yet_another_dict(), '') +class DictMiscTest(unittest.TestCase): + def test_pop_key_error(self): + # tests http://bugs.jython.org/issue2247 + with self.assertRaisesRegexp(KeyError, r"^1$"): + {}.pop(1) + with self.assertRaisesRegexp(KeyError, r"^\(\)$"): + {}.pop(()) + with self.assertRaisesRegexp(KeyError, r"^frozenset\(\[\]\)$"): + {}.pop(frozenset()) + class DerivedDictTest(unittest.TestCase): "Tests for derived dict behaviour" def test_raising_custom_key_error(self): @@ -232,7 +242,13 @@ def test_main(): - test_support.run_unittest(DictInitTest, DictCmpTest, DerivedDictTest, JavaIntegrationTest, JavaDictTest) + test_support.run_unittest( + DictInitTest, + DictCmpTest, + DictMiscTest, + DerivedDictTest, + JavaIntegrationTest, + JavaDictTest) if __name__ == '__main__': test_main() diff --git a/src/org/python/core/PyDictionary.java b/src/org/python/core/PyDictionary.java --- a/src/org/python/core/PyDictionary.java +++ b/src/org/python/core/PyDictionary.java @@ -618,7 +618,7 @@ final PyObject dict_pop(PyObject key, PyObject defaultValue) { if (!getMap().containsKey(key)) { if (defaultValue == null) { - throw Py.KeyError(key.toString()); + throw Py.KeyError(key); } return defaultValue; } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 7 01:50:24 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 07 Jan 2015 00:50:24 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_os=2Esystem_now_uses_a_simp?= =?utf-8?q?ler_wrapping_of_ProcessBuilder?= Message-ID: <20150107005005.11579.46192@psf.io> https://hg.python.org/jython/rev/7ea0c8aa8b50 changeset: 7515:7ea0c8aa8b50 user: Jim Baker date: Tue Jan 06 17:50:03 2015 -0700 summary: os.system now uses a simpler wrapping of ProcessBuilder Previously os.system used subprocess.call, via subprocess.Popen, following the recipe described by https://docs.python.org/2/library/subprocess.html#replacing-os-system However, Popen is substantially (!) more complex than what os.system needs and may be causing issues on systems like HPUX. Simplified os.system accordingly so that it uses subprocess to determine shell executable and support for shell parseability, but otherwise only uses ProcessBuilder. Part of a fix for http://bugs.jython.org/issue2238 files: Lib/os.py | 6 ++- Lib/subprocess.py | 23 ++++++++++ src/org/python/modules/posix/PosixModule.java | 9 --- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -219,7 +219,7 @@ except error: pass -__all__.extend(["makedirs", "removedirs", "renames"]) +__all__.extend(["makedirs", "removedirs", "renames", "system"]) def walk(top, topdown=True, onerror=None, followlinks=False): """Directory tree generator. @@ -719,3 +719,7 @@ return getattr(self._stream, name) def __iter__(self): return iter(self._stream) + + +# Recursive import! So need to put it at the end +from subprocess import _os_system as system diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1824,6 +1824,29 @@ self.send_signal(signal.SIGKILL) +# we need some functionality from subprocess given brokenness for ProcessBuilder, +# but need to avoid recursive imports + +def _os_system(command): + """system(command) -> exit_status + + Execute the command (a string) in a subshell.""" + args = _cmdline2listimpl(command) + args = _escape_args(args) + args = _shell_command + args + cwd = os.getcwd() + builder = java.lang.ProcessBuilder(args) + builder.directory(java.io.File(cwd)) + builder.redirectInput(java.lang.ProcessBuilder.Redirect.INHERIT) + builder.redirectOutput(java.lang.ProcessBuilder.Redirect.INHERIT) + builder.redirectError(java.lang.ProcessBuilder.Redirect.INHERIT) + try: + return builder.start().waitFor() + except (java.io.IOException, + java.lang.IllegalArgumentException), e: + raise OSError(e.getMessage() or e) + + def _demo_posix(): # # Example 1: Simple redirection: Get process list diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java --- a/src/org/python/modules/posix/PosixModule.java +++ b/src/org/python/modules/posix/PosixModule.java @@ -709,15 +709,6 @@ } } - public static PyString __doc__system = new PyString( - "system(command) -> exit_status\n\n" + - "Execute the command (a string) in a subshell."); - public static PyObject system(PyObject command) { - // import subprocess; return subprocess.call(command, shell=True) - return imp.load("subprocess").invoke("call", command, new PyObject[] {Py.True}, - new String[] {"shell"}); - } - public static PyString __doc__umask = new PyString( "umask(new_mask) -> old_mask\n\n" + "Set the current numeric umask and return the previous umask."); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Jan 8 01:08:36 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Thu, 08 Jan 2015 00:08:36 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Mirror_some_Python=2Eg_chan?= =?utf-8?q?ges_in_PythonPartial=2Eg=2E?= Message-ID: <20150108000834.72555.54697@psf.io> https://hg.python.org/jython/rev/42195e1e5515 changeset: 7516:42195e1e5515 user: Frank Wierzbicki date: Thu Jan 08 00:08:32 2015 +0000 summary: Mirror some Python.g changes in PythonPartial.g. files: grammar/Python.g | 2 - grammar/PythonPartial.g | 81 ++++++++++++++++++---------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/grammar/Python.g b/grammar/Python.g --- a/grammar/Python.g +++ b/grammar/Python.g @@ -1992,8 +1992,6 @@ //dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | // (test (comp_for | (',' test)* [','])) ) - -//dictmaker: test ':' test (',' test ':' test)* [','] dictorsetmaker[Token lcurly] @init { List gens = new ArrayList(); diff --git a/grammar/PythonPartial.g b/grammar/PythonPartial.g --- a/grammar/PythonPartial.g +++ b/grammar/PythonPartial.g @@ -182,6 +182,18 @@ | ) ; +/* +//FIXME: something like this needed: + +//not in CPython's Grammar file +// This is used to allow PRINT as a NAME for the __future__ print_function. +name_or_print + : NAME + | {printFunction}? => PRINT + } + ; + +*/ //attr is here for Java compatibility. A Java foo.getIf() can be called from Jython as foo.if // so we need to support any keyword as an attribute. @@ -527,14 +539,14 @@ )? ; -//with_stmt: 'with' test [ with_var ] ':' suite +//with_stmt: 'with' with_item (',' with_item)* ':' suite with_stmt - : WITH test (with_var)? COLON suite + : WITH with_item (options {greedy=true;}:COMMA with_item)* COLON suite ; -//with_var: ('as' | NAME) expr -with_var - : (AS | NAME) expr +//with_item: test ['as' expr] +with_item + : test (AS expr)? ; //except_clause: 'except' [test [('as' | ',') test]] @@ -697,7 +709,7 @@ //atom: ('(' [yield_expr|testlist_gexp] ')' | // '[' [listmaker] ']' | -// '{' [dictmaker] '}' | +// '{' [dictorsetmaker] '}' | // '`' testlist1 '`' | // NAME | NUMBER | STRING+) atom @@ -713,7 +725,7 @@ ) RBRACK | LCURLY - (dictmaker + (dictorsetmaker | ) RCURLY @@ -736,12 +748,12 @@ ) (COMMA)? ; -//testlist_gexp: test ( gen_for | (',' test)* [','] ) +//testlist_gexp: test ( comp_for | (',' test)* [','] ) testlist_gexp : test ( ((options {k=2;}: COMMA test)* (COMMA)? ) - | (gen_for + | (comp_for ) ) ; @@ -804,11 +816,20 @@ | test ; -//dictmaker: test ':' test (',' test ':' test)* [','] -dictmaker - : test COLON test - (options {k=2;}:COMMA test COLON test)* - (COMMA)? +//dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | +// (test (comp_for | (',' test)* [','])) ) +dictorsetmaker + : test + ( + (COLON test + ( comp_for + | (options {k=2;}:COMMA test COLON test)* + ) + |(COMMA test)* + ) + (COMMA)? + | comp_for + ) ; //classdef: 'class' NAME ['(' [testlist] ')'] ':' suite @@ -816,23 +837,25 @@ : decorators? CLASS NAME (LPAREN testlist? RPAREN)? COLON suite ; -//arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) +//arglist: (argument ',')* (argument [','] +// |'*' test (',' argument)* [',' '**' test] +// |'**' test) arglist : argument (COMMA argument)* (COMMA - ( STAR test (COMMA DOUBLESTAR test)? + ( STAR test (COMMA argument)* (COMMA DOUBLESTAR test)? | DOUBLESTAR test )? )? - | STAR test (COMMA DOUBLESTAR test)? + | STAR test (COMMA argument)* (COMMA DOUBLESTAR test)? | DOUBLESTAR test ; -//argument: test [gen_for] | test '=' test # Really [keyword '='] test +//argument: test [comp_for] | test '=' test # Really [keyword '='] test argument : test ((ASSIGN test) - | gen_for + | comp_for | ) ; @@ -853,20 +876,20 @@ : IF test (list_iter)? ; -//gen_iter: gen_for | gen_if -gen_iter - : gen_for - | gen_if +//comp_iter: comp_for | comp_if +comp_iter + : comp_for + | comp_if ; -//gen_for: 'for' exprlist 'in' or_test [gen_iter] -gen_for - : FOR exprlist IN or_test gen_iter? +//comp_for: 'for' exprlist 'in' or_test [comp_iter] +comp_for + : FOR exprlist IN or_test comp_iter? ; -//gen_if: 'if' old_test [gen_iter] -gen_if - : IF test gen_iter? +//comp_if: 'if' old_test [comp_iter] +comp_if + : IF test comp_iter? ; //yield_expr: 'yield' [testlist] -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Jan 8 05:07:44 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 08 Jan 2015 04:07:44 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Raises_NotImplementedError_?= =?utf-8?q?if_abstract_method_from_Java_is_not_implemented?= Message-ID: <20150108040742.11571.99237@psf.io> https://hg.python.org/jython/rev/3235ec531b41 changeset: 7517:3235ec531b41 user: Jim Baker date: Wed Jan 07 21:06:17 2015 -0700 summary: Raises NotImplementedError if abstract method from Java is not implemented Abstract methods of an inherited class or interface from Java now raise NotImplementedError, instead of returning None (in Java, null) or some "zero", if they are not implemented in the extending Python class. This is a (minor) backwards breaking change similar to other recent changes to remove silent errors in Java integration. Unlike ABCs in Python - or partial extensions of abstract classes in Java - we allow such classes to be instantiated. We may wish to change this in Jython 3.x, but it seems too radical of a change for the moment. Example: here is the decompiled bytecode for a class implementing Callable with a method body for the call abstract method like so: public Object call() throws Exception { final PyObject findPython = ProxyMaker.findPython((PyProxy)this, "call"); if (findPython != null) { final PyObject pyObject = findPython; try { return Py.tojava( pyObject._jcallexc((Object[])Py.EmptyObjects), (Class)Class.forName("java.lang.Object")); } catch (Exception ex) { throw ex; } catch (Throwable t) { pyObject._jthrow(t); return null; } } throw (Throwable)Py.NotImplementedError(""); } Previously the last line of this method would have returned null, or some "zero", per the return type, if it could not look up a method in the extending Python class. Fixes http://bugs.jython.org/issue1561 files: Lib/test/test_java_subclasses.py | 77 +++++++++++- src/org/python/compiler/ProxyMaker.java | 13 ++ 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_java_subclasses.py b/Lib/test/test_java_subclasses.py --- a/Lib/test/test_java_subclasses.py +++ b/Lib/test/test_java_subclasses.py @@ -7,7 +7,7 @@ from java.lang import (Boolean, Class, ClassLoader, Comparable,Integer, Object, Runnable, String, Thread, ThreadGroup) -from java.util import Date, Hashtable, Vector +from java.util import AbstractList, Date, Hashtable, HashSet, Vector from java.util.concurrent import Callable, Executors from java.awt import Color, Component, Dimension, Rectangle @@ -374,14 +374,75 @@ pool.shutdown() +class AbstractMethodTest(unittest.TestCase): + + def test_abstract_method_implemented(self): + class C(AbstractList): + def get(self, index): + return index * 2 + def size(self): + return 7 + + c = C() + self.assertEqual(c.size(), 7) + self.assertEqual([c.get(i) for i in xrange(7)], range(0, 14, 2)) + + def test_abstract_method_not_implemented(self): + class C(AbstractList): + def size(self): + return 47 + + # note that unlike ABCs in Python - or partial extensions + # of abstract classes in Java - we allow such classes to + # be instantiated. We may wish to change this in Jython + # 3.x + c = C() + self.assertEqual(c.size(), 47) + with self.assertRaisesRegexp(NotImplementedError, r"^$"): + C().get(42) + + def test_concrete_method(self): + class H(HashSet): + def __init__(self): + self.added = 0 + HashSet.__init__(self) + + def add(self, value): + self.added += 1 + HashSet.add(self, value) + + h = H() + h.add(42) + h.add(47) + h.discard(47) + self.assertEqual(list(h), [42]) + self.assertEqual(h.added, 2) + + def test_interface_method_implemented(self): + class C(Callable): + def call(self): + return 42 + + self.assertEqual(C().call(), 42) + + def test_interface_method_not_implemented(self): + class C(Callable): + pass + + with self.assertRaisesRegexp(NotImplementedError, r"^$"): + C().call() + + def test_main(): - test_support.run_unittest(InterfaceTest, - TableModelTest, - AutoSuperTest, - PythonSubclassesTest, - AbstractOnSyspathTest, - ContextClassloaderTest, - MetaClassTest) + test_support.run_unittest( + InterfaceTest, + TableModelTest, + AutoSuperTest, + PythonSubclassesTest, + AbstractOnSyspathTest, + ContextClassloaderTest, + MetaClassTest, + AbstractMethodTest) if __name__ == '__main__': diff --git a/src/org/python/compiler/ProxyMaker.java b/src/org/python/compiler/ProxyMaker.java --- a/src/org/python/compiler/ProxyMaker.java +++ b/src/org/python/compiler/ProxyMaker.java @@ -10,8 +10,12 @@ import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.python.core.Py; +import org.python.core.PyException; import org.python.util.Generic; +import static org.python.util.CodegenUtils.p; +import static org.python.util.CodegenUtils.sig; + public class ProxyMaker extends ProxyCodeHelpers implements ClassConstants, Opcodes { @@ -382,6 +386,15 @@ callMethod(code, name, parameters, ret, exceptions); code.label(returnNull); code.pop(); + + // throw an exception if we cannot load a Python method for this abstract method + // note that the unreachable return is simply to simplify bytecode gen + code.ldc(""); + code.invokestatic(p(Py.class), "NotImplementedError", + sig(PyException.class, String.class)); + code.checkcast(p(Throwable.class)); + code.athrow(); + doNullReturn(code, ret); } } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Jan 8 16:02:35 2015 From: jython-checkins at python.org (alex.gronholm) Date: Thu, 08 Jan 2015 15:02:35 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Use_already_defined_=5Fwin?= =?utf-8?q?=5Foses_instead_of_hard-coded_=27nt=27=2E?= Message-ID: <20150108150202.8745.68686@psf.io> https://hg.python.org/jython/rev/2ffae23d1e07 changeset: 7519:2ffae23d1e07 user: Pekka Kl?rck date: Thu Jan 08 16:34:34 2015 +0200 summary: Use already defined _win_oses instead of hard-coded 'nt'. Would probably be better to define `mswindows_jython = os._name == 'nt'` instead of using `os._name in _win_oses` in general, but that's outside the scope of this pr. files: Lib/subprocess.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1366,7 +1366,7 @@ else: return field - if os._name != 'nt': + if os._name not in _win_oses: def _get_pid(self, pid_field='pid'): field = self._get_private_field(self._process, pid_field) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Jan 8 16:02:35 2015 From: jython-checkins at python.org (alex.gronholm) Date: Thu, 08 Jan 2015 15:02:35 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Implement_Popen=2Epid_=28ht?= =?utf-8?q?tp=3A//bugs=2Ejython=2Eorg/issue2221=29?= Message-ID: <20150108150202.72555.34395@psf.io> https://hg.python.org/jython/rev/593d5c73444b changeset: 7518:593d5c73444b user: Pekka Kl?rck date: Thu Jan 08 16:34:28 2015 +0200 summary: Implement Popen.pid (http://bugs.jython.org/issue2221) This code has been tested on Linux and Windows 7, and same approach was tested earlier also on OSX. If underlying Process implementation is not what we expect (i.e. doesn't have 'pid' or 'handle' field, depending on OS), pid will be None. This functionality is tested by querying a non-existing field. Pid would also be None if a security manager would restricts reading aforementioned private fields. In practice execution stops already in '_setup_env' under such security manager, though. files: Lib/subprocess.py | 34 ++++++++++++++++++++++ Lib/test/test_subprocess_jy.py | 18 +++++++++++ 2 files changed, 52 insertions(+), 0 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1350,9 +1350,43 @@ except (java.io.IOException, java.lang.IllegalArgumentException), e: raise OSError(e.getMessage() or e) + self.pid = self._get_pid() self._child_created = True + # Getting pid based on http://stackoverflow.com/questions/4750470 + + def _get_private_field(self, object, field_name): + try: + field = object.getClass().getDeclaredField(field_name) + field.setAccessible(True) + except (java.lang.NoSuchFieldException, + java.lang.SecurityException): + return None + else: + return field + + if os._name != 'nt': + + def _get_pid(self, pid_field='pid'): + field = self._get_private_field(self._process, pid_field) + if field is None: + return None + return field.getInt(self._process) + + else: + + import ctypes + _handle_to_pid = ctypes.cdll.kernel32.GetProcessId + _handle_to_pid.argtypes = (ctypes.c_long,) + + def _get_pid(self, handle_field='handle'): + field = self._get_private_field(self._process, handle_field) + if field is None: + return None + return self._handle_to_pid(field.getLong(self._process)) + + def poll(self, _deadstate=None): """Check if child process has terminated. Returns returncode attribute.""" diff --git a/Lib/test/test_subprocess_jy.py b/Lib/test/test_subprocess_jy.py --- a/Lib/test/test_subprocess_jy.py +++ b/Lib/test/test_subprocess_jy.py @@ -5,6 +5,23 @@ from test import test_support from subprocess import PIPE, Popen, _cmdline2list + +class PidTest(unittest.TestCase): + + def testPid(self): + # Cannot use sys.executable here because it's a script and has different + # pid than the actual started Java process. + p = Popen(['python', '-c', 'import os; print os.getpid()'], + stdout=PIPE) + p.wait() + self.assertEquals(int(p.stdout.read()), p.pid) + + def testNonExistingField(self): + # Test we don't crash if Process class doesn't have field we need. + p = Popen(['echo foo'], shell=True, stdout=PIPE) + self.assertIsNone(p._get_pid('nonex')) + + class EnvironmentInheritanceTest(unittest.TestCase): def testDefaultEnvIsInherited(self): @@ -70,6 +87,7 @@ def test_main(): test_support.run_unittest( + PidTest, EnvironmentInheritanceTest, JythonOptsTest, Cmdline2ListTestCase) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Jan 8 23:17:49 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 08 Jan 2015 22:17:49 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_ant_regrtest_will_now_run_s?= =?utf-8?q?ubprocess_and_network_resource_tests?= Message-ID: <20150108221749.72569.5468@psf.io> https://hg.python.org/jython/rev/a7b3aa073620 changeset: 7520:a7b3aa073620 user: Jim Baker date: Thu Jan 08 15:17:43 2015 -0700 summary: ant regrtest will now run subprocess and network resource tests Also minor fixes to test_glob, test_urllibnet, test_urllib2net, as well as some missing functionality in socket and ssl support. files: Lib/_socket.py | 18 +- Lib/ssl.py | 16 +- Lib/test/test_glob.py | 187 ++++++++++++ Lib/test/test_imaplib.py | 242 ++++++++++++++++ Lib/test/test_robotparser.py | 261 ------------------ Lib/test/test_ssl.py | 2 +- Lib/test/test_subprocess.py | 2 +- Lib/test/test_urllib2net.py | 332 +++++++++++++++++++++++ Lib/test/test_urllibnet.py | 219 +++++++++++++++ build.xml | 4 + 10 files changed, 1014 insertions(+), 269 deletions(-) diff --git a/Lib/_socket.py b/Lib/_socket.py --- a/Lib/_socket.py +++ b/Lib/_socket.py @@ -24,6 +24,7 @@ from java.lang import Thread, IllegalStateException from java.net import InetAddress, InetSocketAddress from java.nio.channels import ClosedChannelException +from java.security.cert import CertificateException from java.util import NoSuchElementException from java.util.concurrent import ( ArrayBlockingQueue, CopyOnWriteArrayList, CountDownLatch, LinkedBlockingQueue, @@ -317,16 +318,23 @@ java.nio.channels.UnsupportedAddressTypeException : None, SSLPeerUnverifiedException: lambda x: SSLError(SSL_ERROR_SSL, x.message), - SSLException: lambda x: SSLError(SSL_ERROR_SSL, x.message), } def _map_exception(java_exception): - mapped_exception = _exception_map.get(java_exception.__class__) - if mapped_exception: - py_exception = mapped_exception(java_exception) + if isinstance(java_exception, SSLException) or isinstance(java_exception, CertificateException): + cause = java_exception.cause + if cause: + msg = "%s (%s)" % (java_exception.message, cause) + else: + msg = java_exception.message + py_exception = SSLError(SSL_ERROR_SSL, msg) else: - py_exception = error(-1, 'Unmapped exception: %s' % java_exception) + mapped_exception = _exception_map.get(java_exception.__class__) + if mapped_exception: + py_exception = mapped_exception(java_exception) + else: + py_exception = error(-1, 'Unmapped exception: %s' % java_exception) py_exception.java_exception = java_exception return _add_exception_attrs(py_exception) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -26,7 +26,8 @@ SSL_ERROR_WANT_CONNECT, SSL_ERROR_EOF, SSL_ERROR_INVALID_ERROR_CODE, - error as socket_error) + error as socket_error, + CLIENT_SOCKET, DATAGRAM_SOCKET) from _sslcerts import _get_ssl_context from java.text import SimpleDateFormat @@ -158,12 +159,16 @@ def send(self, data): return self.sock.send(data) + write = send + def sendall(self, data): return self.sock.sendall(data) def recv(self, bufsize, flags=0): return self.sock.recv(bufsize, flags) + read = recv + def recvfrom(self, bufsize, flags=0): return self.sock.recvfrom(bufsize, flags) @@ -196,6 +201,14 @@ # Need to work with the real underlying socket as well + def pending(self): + # undocumented function, used by some tests + # see also http://bugs.python.org/issue21430 + if self._sock.socket_type == CLIENT_SOCKET or self._sock.socket_type == DATAGRAM_SOCKET: + if self._sock.incoming_head is not None: + return self._sock.incoming_head.readableBytes() + return 0 + def _readable(self): return self._sock._readable() @@ -260,6 +273,7 @@ # ssl_version - use SSLEngine.setEnabledProtocols(java.lang.String[]) # ciphers - SSLEngine.setEnabledCipherSuites(String[] suites) + at raises_java_exception def wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=None, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None): diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_glob.py @@ -0,0 +1,187 @@ +import glob +import os +import shutil +import sys +import unittest + +from test.test_support import run_unittest, TESTFN + + +def fsdecode(s): + return unicode(s, sys.getfilesystemencoding()) + + +class GlobTests(unittest.TestCase): + + def norm(self, *parts): + return os.path.normpath(os.path.join(self.tempdir, *parts)) + + def mktemp(self, *parts): + filename = self.norm(*parts) + base, file = os.path.split(filename) + if not os.path.exists(base): + os.makedirs(base) + f = open(filename, 'w') + f.close() + + def setUp(self): + self.tempdir = TESTFN + "_dir" + self.mktemp('a', 'D') + self.mktemp('aab', 'F') + self.mktemp('.aa', 'G') + self.mktemp('.bb', 'H') + self.mktemp('aaa', 'zzzF') + self.mktemp('ZZZ') + self.mktemp('a', 'bcd', 'EF') + self.mktemp('a', 'bcd', 'efg', 'ha') + if hasattr(os, 'symlink'): + os.symlink(self.norm('broken'), self.norm('sym1')) + os.symlink('broken', self.norm('sym2')) + os.symlink(os.path.join('a', 'bcd'), self.norm('sym3')) + + def tearDown(self): + shutil.rmtree(self.tempdir) + + def glob(self, *parts): + if len(parts) == 1: + pattern = parts[0] + else: + pattern = os.path.join(*parts) + p = os.path.join(self.tempdir, pattern) + res = glob.glob(p) + self.assertEqual(list(glob.iglob(p)), res) + ures = [fsdecode(x) for x in res] + self.assertEqual(glob.glob(fsdecode(p)), ures) + self.assertEqual(list(glob.iglob(fsdecode(p))), ures) + return res + + def assertSequencesEqual_noorder(self, l1, l2): + l1 = list(l1) + l2 = list(l2) + self.assertEqual(set(l1), set(l2)) + self.assertEqual(sorted(l1), sorted(l2)) + + def test_glob_literal(self): + eq = self.assertSequencesEqual_noorder + eq(self.glob('a'), [self.norm('a')]) + eq(self.glob('a', 'D'), [self.norm('a', 'D')]) + eq(self.glob('aab'), [self.norm('aab')]) + eq(self.glob('zymurgy'), []) + + res = glob.glob('*') + # For a clean checkout, the next two assertions would never + # have failed, even with the change with Jython in + # https://hg.python.org/jython/rev/ea036792f304 + # + # But for developers playing with things, we should not have + # it fail either + self.assertLessEqual({type(r) for r in res}, {str, unicode}) + res = glob.glob(os.path.join(os.curdir, '*')) + self.assertLessEqual({type(r) for r in res}, {str, unicode}) + + # test return types are unicode, but only if os.listdir + # returns unicode filenames + tmp = os.listdir(fsdecode(os.curdir)) + if {type(x) for x in tmp} == {unicode}: + res = glob.glob(u'*') + self.assertEqual({type(r) for r in res}, {unicode}) + res = glob.glob(os.path.join(fsdecode(os.curdir), u'*')) + self.assertEqual({type(r) for r in res}, {unicode}) + + def test_glob_one_directory(self): + eq = self.assertSequencesEqual_noorder + eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa'])) + eq(self.glob('*a'), map(self.norm, ['a', 'aaa'])) + eq(self.glob('.*'), map(self.norm, ['.aa', '.bb'])) + eq(self.glob('?aa'), map(self.norm, ['aaa'])) + eq(self.glob('aa?'), map(self.norm, ['aaa', 'aab'])) + eq(self.glob('aa[ab]'), map(self.norm, ['aaa', 'aab'])) + eq(self.glob('*q'), []) + + def test_glob_nested_directory(self): + eq = self.assertSequencesEqual_noorder + if os.path.normcase("abCD") == "abCD": + # case-sensitive filesystem + eq(self.glob('a', 'bcd', 'E*'), [self.norm('a', 'bcd', 'EF')]) + else: + # case insensitive filesystem + eq(self.glob('a', 'bcd', 'E*'), [self.norm('a', 'bcd', 'EF'), + self.norm('a', 'bcd', 'efg')]) + eq(self.glob('a', 'bcd', '*g'), [self.norm('a', 'bcd', 'efg')]) + + def test_glob_directory_names(self): + eq = self.assertSequencesEqual_noorder + eq(self.glob('*', 'D'), [self.norm('a', 'D')]) + eq(self.glob('*', '*a'), []) + eq(self.glob('a', '*', '*', '*a'), + [self.norm('a', 'bcd', 'efg', 'ha')]) + eq(self.glob('?a?', '*F'), [self.norm('aaa', 'zzzF'), + self.norm('aab', 'F')]) + + def test_glob_directory_with_trailing_slash(self): + # Patterns ending with a slash shouldn't match non-dirs + res = glob.glob(self.norm('Z*Z') + os.sep) + self.assertEqual(res, []) + res = glob.glob(self.norm('ZZZ') + os.sep) + self.assertEqual(res, []) + # When there is a wildcard pattern which ends with os.sep, glob() + # doesn't blow up. + res = glob.glob(self.norm('aa*') + os.sep) + self.assertEqual(len(res), 2) + # either of these results is reasonable + self.assertIn(set(res), [ + {self.norm('aaa'), self.norm('aab')}, + {self.norm('aaa') + os.sep, self.norm('aab') + os.sep}, + ]) + + def test_glob_unicode_directory_with_trailing_slash(self): + # Same as test_glob_directory_with_trailing_slash, but with an + # unicode argument. + res = glob.glob(fsdecode(self.norm('Z*Z') + os.sep)) + self.assertEqual(res, []) + res = glob.glob(fsdecode(self.norm('ZZZ') + os.sep)) + self.assertEqual(res, []) + res = glob.glob(fsdecode(self.norm('aa*') + os.sep)) + self.assertEqual(len(res), 2) + # either of these results is reasonable + self.assertIn(set(res), [ + {fsdecode(self.norm('aaa')), fsdecode(self.norm('aab'))}, + {fsdecode(self.norm('aaa') + os.sep), + fsdecode(self.norm('aab') + os.sep)}, + ]) + + @unittest.skipUnless(hasattr(os, 'symlink'), "Requires symlink support") + def test_glob_symlinks(self): + eq = self.assertSequencesEqual_noorder + eq(self.glob('sym3'), [self.norm('sym3')]) + eq(self.glob('sym3', '*'), [self.norm('sym3', 'EF'), + self.norm('sym3', 'efg')]) + self.assertIn(self.glob('sym3' + os.sep), + [[self.norm('sym3')], [self.norm('sym3') + os.sep]]) + eq(self.glob('*', '*F'), + [self.norm('aaa', 'zzzF'), self.norm('aab', 'F'), + self.norm('sym3', 'EF')]) + + @unittest.skipUnless(hasattr(os, 'symlink'), "Requires symlink support") + def test_glob_broken_symlinks(self): + eq = self.assertSequencesEqual_noorder + eq(self.glob('sym*'), [self.norm('sym1'), self.norm('sym2'), + self.norm('sym3')]) + eq(self.glob('sym1'), [self.norm('sym1')]) + eq(self.glob('sym2'), [self.norm('sym2')]) + + @unittest.skipUnless(sys.platform == "win32", "Win32 specific test") + def test_glob_magic_in_drive(self): + eq = self.assertSequencesEqual_noorder + eq(glob.glob('*:'), []) + eq(glob.glob(u'*:'), []) + eq(glob.glob('?:'), []) + eq(glob.glob(u'?:'), []) + + +def test_main(): + run_unittest(GlobTests) + + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_imaplib.py @@ -0,0 +1,242 @@ +from test import test_support as support +# If we end up with a significant number of tests that don't require +# threading, this test module should be split. Right now we skip +# them all if we don't have threading. +threading = support.import_module('threading') + +from contextlib import contextmanager +import imaplib +import os.path +import SocketServer +import time + +from test.test_support import reap_threads, verbose, transient_internet, is_jython +import unittest + +try: + import ssl +except ImportError: + ssl = None + +CERTFILE = None + + +class TestImaplib(unittest.TestCase): + + def test_that_Time2Internaldate_returns_a_result(self): + # We can check only that it successfully produces a result, + # not the correctness of the result itself, since the result + # depends on the timezone the machine is in. + timevalues = [2000000000, 2000000000.0, time.localtime(2000000000), + '"18-May-2033 05:33:20 +0200"'] + + for t in timevalues: + imaplib.Time2Internaldate(t) + + +if ssl: + + class SecureTCPServer(SocketServer.TCPServer): + + def get_request(self): + newsocket, fromaddr = self.socket.accept() + connstream = ssl.wrap_socket(newsocket, + server_side=True, + ca_certs=CERTFILE, + certfile=CERTFILE) + return connstream, fromaddr + + IMAP4_SSL = imaplib.IMAP4_SSL + +else: + + class SecureTCPServer: + pass + + IMAP4_SSL = None + + +class SimpleIMAPHandler(SocketServer.StreamRequestHandler): + + timeout = 1 + + def _send(self, message): + if verbose: print "SENT:", message.strip() + self.wfile.write(message) + + def handle(self): + # Send a welcome message. + self._send('* OK IMAP4rev1\r\n') + while 1: + # Gather up input until we receive a line terminator or we timeout. + # Accumulate read(1) because it's simpler to handle the differences + # between naked sockets and SSL sockets. + line = '' + while 1: + try: + part = self.rfile.read(1) + if part == '': + # Naked sockets return empty strings.. + return + line += part + except IOError: + # ..but SSLSockets raise exceptions. + return + if line.endswith('\r\n'): + break + + if verbose: print 'GOT:', line.strip() + splitline = line.split() + tag = splitline[0] + cmd = splitline[1] + args = splitline[2:] + + if hasattr(self, 'cmd_%s' % (cmd,)): + getattr(self, 'cmd_%s' % (cmd,))(tag, args) + else: + self._send('%s BAD %s unknown\r\n' % (tag, cmd)) + + def cmd_CAPABILITY(self, tag, args): + self._send('* CAPABILITY IMAP4rev1\r\n') + self._send('%s OK CAPABILITY completed\r\n' % (tag,)) + + +class BaseThreadedNetworkedTests(unittest.TestCase): + + def make_server(self, addr, hdlr): + + class MyServer(self.server_class): + def handle_error(self, request, client_address): + self.close_request(request) + self.server_close() + raise + + if verbose: print "creating server" + server = MyServer(addr, hdlr) + self.assertEqual(server.server_address, server.socket.getsockname()) + + if verbose: + print "server created" + print "ADDR =", addr + print "CLASS =", self.server_class + print "HDLR =", server.RequestHandlerClass + + t = threading.Thread( + name='%s serving' % self.server_class, + target=server.serve_forever, + # Short poll interval to make the test finish quickly. + # Time between requests is short enough that we won't wake + # up spuriously too many times. + kwargs={'poll_interval':0.01}) + t.daemon = True # In case this function raises. + t.start() + if verbose: print "server running" + return server, t + + def reap_server(self, server, thread): + if verbose: print "waiting for server" + server.shutdown() + thread.join() + if verbose: print "done" + + @contextmanager + def reaped_server(self, hdlr): + server, thread = self.make_server((support.HOST, 0), hdlr) + try: + yield server + finally: + self.reap_server(server, thread) + + @reap_threads + def test_connect(self): + with self.reaped_server(SimpleIMAPHandler) as server: + client = self.imap_class(*server.server_address) + client.shutdown() + + @reap_threads + def test_issue5949(self): + + class EOFHandler(SocketServer.StreamRequestHandler): + def handle(self): + # EOF without sending a complete welcome message. + self.wfile.write('* OK') + + with self.reaped_server(EOFHandler) as server: + self.assertRaises(imaplib.IMAP4.abort, + self.imap_class, *server.server_address) + + +class ThreadedNetworkedTests(BaseThreadedNetworkedTests): + + server_class = SocketServer.TCPServer + imap_class = imaplib.IMAP4 + + + at unittest.skipIf(is_jython, "imaplib does not support passing in ca_certs; verifiable certs are necessary on Jython") + at unittest.skipUnless(ssl, "SSL not available") +class ThreadedNetworkedTestsSSL(BaseThreadedNetworkedTests): + + server_class = SecureTCPServer + imap_class = IMAP4_SSL + + +class RemoteIMAPTest(unittest.TestCase): + host = 'cyrus.andrew.cmu.edu' + port = 143 + username = 'anonymous' + password = 'pass' + imap_class = imaplib.IMAP4 + + def setUp(self): + with transient_internet(self.host): + self.server = self.imap_class(self.host, self.port) + + def tearDown(self): + if self.server is not None: + self.server.logout() + + def test_logincapa(self): + self.assertTrue('LOGINDISABLED' in self.server.capabilities) + + def test_anonlogin(self): + self.assertTrue('AUTH=ANONYMOUS' in self.server.capabilities) + rs = self.server.login(self.username, self.password) + self.assertEqual(rs[0], 'OK') + + def test_logout(self): + rs = self.server.logout() + self.server = None + self.assertEqual(rs[0], 'BYE') + + + at unittest.skipUnless(ssl, "SSL not available") +class RemoteIMAP_SSLTest(RemoteIMAPTest): + port = 993 + imap_class = IMAP4_SSL + + def test_logincapa(self): + self.assertFalse('LOGINDISABLED' in self.server.capabilities) + self.assertTrue('AUTH=PLAIN' in self.server.capabilities) + + +def test_main(): + tests = [TestImaplib] + + if support.is_resource_enabled('network'): + if ssl: + global CERTFILE + CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, + "keycert.pem") + if not os.path.exists(CERTFILE): + raise support.TestFailed("Can't read certificate files!") + tests.extend([ + ThreadedNetworkedTests, ThreadedNetworkedTestsSSL, + RemoteIMAPTest, RemoteIMAP_SSLTest, + ]) + + support.run_unittest(*tests) + + +if __name__ == "__main__": + support.use_resources = ['network'] + test_main() diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py deleted file mode 100644 --- a/Lib/test/test_robotparser.py +++ /dev/null @@ -1,261 +0,0 @@ -import unittest, StringIO, robotparser -from test import test_support - -class RobotTestCase(unittest.TestCase): - def __init__(self, index, parser, url, good, agent): - unittest.TestCase.__init__(self) - if good: - self.str = "RobotTest(%d, good, %s)" % (index, url) - else: - self.str = "RobotTest(%d, bad, %s)" % (index, url) - self.parser = parser - self.url = url - self.good = good - self.agent = agent - - def runTest(self): - if isinstance(self.url, tuple): - agent, url = self.url - else: - url = self.url - agent = self.agent - if self.good: - self.assertTrue(self.parser.can_fetch(agent, url)) - else: - self.assertFalse(self.parser.can_fetch(agent, url)) - - def __str__(self): - return self.str - -tests = unittest.TestSuite() - -def RobotTest(index, robots_txt, good_urls, bad_urls, - agent="test_robotparser"): - - lines = StringIO.StringIO(robots_txt).readlines() - parser = robotparser.RobotFileParser() - parser.parse(lines) - for url in good_urls: - tests.addTest(RobotTestCase(index, parser, url, 1, agent)) - for url in bad_urls: - tests.addTest(RobotTestCase(index, parser, url, 0, agent)) - -# Examples from http://www.robotstxt.org/wc/norobots.html (fetched 2002) - -# 1. -doc = """ -User-agent: * -Disallow: /cyberworld/map/ # This is an infinite virtual URL space -Disallow: /tmp/ # these will soon disappear -Disallow: /foo.html -""" - -good = ['/','/test.html'] -bad = ['/cyberworld/map/index.html','/tmp/xxx','/foo.html'] - -RobotTest(1, doc, good, bad) - -# 2. -doc = """ -# robots.txt for http://www.example.com/ - -User-agent: * -Disallow: /cyberworld/map/ # This is an infinite virtual URL space - -# Cybermapper knows where to go. -User-agent: cybermapper -Disallow: - -""" - -good = ['/','/test.html',('cybermapper','/cyberworld/map/index.html')] -bad = ['/cyberworld/map/index.html'] - -RobotTest(2, doc, good, bad) - -# 3. -doc = """ -# go away -User-agent: * -Disallow: / -""" - -good = [] -bad = ['/cyberworld/map/index.html','/','/tmp/'] - -RobotTest(3, doc, good, bad) - -# Examples from http://www.robotstxt.org/wc/norobots-rfc.html (fetched 2002) - -# 4. -doc = """ -User-agent: figtree -Disallow: /tmp -Disallow: /a%3cd.html -Disallow: /a%2fb.html -Disallow: /%7ejoe/index.html -""" - -good = [] # XFAIL '/a/b.html' -bad = ['/tmp','/tmp.html','/tmp/a.html', - '/a%3cd.html','/a%3Cd.html','/a%2fb.html', - '/~joe/index.html' - ] - -RobotTest(4, doc, good, bad, 'figtree') -RobotTest(5, doc, good, bad, 'FigTree Robot libwww-perl/5.04') - -# 6. -doc = """ -User-agent: * -Disallow: /tmp/ -Disallow: /a%3Cd.html -Disallow: /a/b.html -Disallow: /%7ejoe/index.html -""" - -good = ['/tmp',] # XFAIL: '/a%2fb.html' -bad = ['/tmp/','/tmp/a.html', - '/a%3cd.html','/a%3Cd.html',"/a/b.html", - '/%7Ejoe/index.html'] - -RobotTest(6, doc, good, bad) - -# From bug report #523041 - -# 7. -doc = """ -User-Agent: * -Disallow: /. -""" - -good = ['/foo.html'] -bad = [] # Bug report says "/" should be denied, but that is not in the RFC - -RobotTest(7, doc, good, bad) - -# From Google: http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=40364 - -# 8. -doc = """ -User-agent: Googlebot -Allow: /folder1/myfile.html -Disallow: /folder1/ -""" - -good = ['/folder1/myfile.html'] -bad = ['/folder1/anotherfile.html'] - -RobotTest(8, doc, good, bad, agent="Googlebot") - -# 9. This file is incorrect because "Googlebot" is a substring of -# "Googlebot-Mobile", so test 10 works just like test 9. -doc = """ -User-agent: Googlebot -Disallow: / - -User-agent: Googlebot-Mobile -Allow: / -""" - -good = [] -bad = ['/something.jpg'] - -RobotTest(9, doc, good, bad, agent="Googlebot") - -good = [] -bad = ['/something.jpg'] - -RobotTest(10, doc, good, bad, agent="Googlebot-Mobile") - -# 11. Get the order correct. -doc = """ -User-agent: Googlebot-Mobile -Allow: / - -User-agent: Googlebot -Disallow: / -""" - -good = [] -bad = ['/something.jpg'] - -RobotTest(11, doc, good, bad, agent="Googlebot") - -good = ['/something.jpg'] -bad = [] - -RobotTest(12, doc, good, bad, agent="Googlebot-Mobile") - - -# 13. Google also got the order wrong in #8. You need to specify the -# URLs from more specific to more general. -doc = """ -User-agent: Googlebot -Allow: /folder1/myfile.html -Disallow: /folder1/ -""" - -good = ['/folder1/myfile.html'] -bad = ['/folder1/anotherfile.html'] - -RobotTest(13, doc, good, bad, agent="googlebot") - - -# 14. For issue #6325 (query string support) -doc = """ -User-agent: * -Disallow: /some/path?name=value -""" - -good = ['/some/path'] -bad = ['/some/path?name=value'] - -RobotTest(14, doc, good, bad) - -# 15. For issue #4108 (obey first * entry) -doc = """ -User-agent: * -Disallow: /some/path - -User-agent: * -Disallow: /another/path -""" - -good = ['/another/path'] -bad = ['/some/path'] - -RobotTest(15, doc, good, bad) - - -class NetworkTestCase(unittest.TestCase): - - def testPasswordProtectedSite(self): - test_support.requires('network') - with test_support.transient_internet('mueblesmoraleda.com'): - url = 'http://mueblesmoraleda.com' - parser = robotparser.RobotFileParser() - parser.set_url(url) - try: - parser.read() - except IOError: - self.skipTest('%s is unavailable' % url) - self.assertEqual(parser.can_fetch("*", url+"/robots.txt"), False) - - def testPythonOrg(self): - test_support.requires('network') - with test_support.transient_internet('www.python.org'): - parser = robotparser.RobotFileParser( - "http://www.python.org/robots.txt") - parser.read() - self.assertTrue( - parser.can_fetch("*", "http://www.python.org/robots.txt")) - - -def test_main(): - test_support.run_unittest(tests) - test_support.run_unittest(NetworkTestCase) - -if __name__=='__main__': - test_support.verbose = 1 - test_main() diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -181,7 +181,6 @@ with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): s.connect(remote) - @test_support.cpython_only def test_refcycle(self): # Issue #7943: an SSL object doesn't create reference cycles with # itself. @@ -189,6 +188,7 @@ ss = ssl.wrap_socket(s) wr = weakref.ref(ss) del ss + test_support.gc_collect() # Usual Jython requirement self.assertEqual(wr(), None) def test_wrapped_unconnected(self): diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -447,7 +447,7 @@ self.assertEqual(subprocess.list2cmdline(['ab', '']), 'ab ""') self.assertEqual(subprocess.list2cmdline(['echo', 'foo|bar']), - 'echo "foo|bar"') + 'echo foo|bar') def test_poll(self): diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_urllib2net.py @@ -0,0 +1,332 @@ +#!/usr/bin/env python + +import unittest +from test import test_support +from test.test_urllib2 import sanepathname2url + +import socket +import urllib2 +import os +import sys + +TIMEOUT = 60 # seconds + + +def _retry_thrice(func, exc, *args, **kwargs): + for i in range(3): + try: + return func(*args, **kwargs) + except exc, last_exc: + continue + except: + raise + raise last_exc + +def _wrap_with_retry_thrice(func, exc): + def wrapped(*args, **kwargs): + return _retry_thrice(func, exc, *args, **kwargs) + return wrapped + +# Connecting to remote hosts is flaky. Make it more robust by retrying +# the connection several times. +_urlopen_with_retry = _wrap_with_retry_thrice(urllib2.urlopen, urllib2.URLError) + + +class AuthTests(unittest.TestCase): + """Tests urllib2 authentication features.""" + +## Disabled at the moment since there is no page under python.org which +## could be used to HTTP authentication. +# +# def test_basic_auth(self): +# import httplib +# +# test_url = "http://www.python.org/test/test_urllib2/basic_auth" +# test_hostport = "www.python.org" +# test_realm = 'Test Realm' +# test_user = 'test.test_urllib2net' +# test_password = 'blah' +# +# # failure +# try: +# _urlopen_with_retry(test_url) +# except urllib2.HTTPError, exc: +# self.assertEqual(exc.code, 401) +# else: +# self.fail("urlopen() should have failed with 401") +# +# # success +# auth_handler = urllib2.HTTPBasicAuthHandler() +# auth_handler.add_password(test_realm, test_hostport, +# test_user, test_password) +# opener = urllib2.build_opener(auth_handler) +# f = opener.open('http://localhost/') +# response = _urlopen_with_retry("http://www.python.org/") +# +# # The 'userinfo' URL component is deprecated by RFC 3986 for security +# # reasons, let's not implement it! (it's already implemented for proxy +# # specification strings (that is, URLs or authorities specifying a +# # proxy), so we must keep that) +# self.assertRaises(httplib.InvalidURL, +# urllib2.urlopen, "http://evil:thing at example.com") + + +class CloseSocketTest(unittest.TestCase): + + def test_close(self): + import httplib + + # calling .close() on urllib2's response objects should close the + # underlying socket + + # delve deep into response to fetch socket._socketobject + response = _urlopen_with_retry("http://www.python.org/") + abused_fileobject = response.fp + self.assertTrue(abused_fileobject.__class__ is socket._fileobject) + httpresponse = abused_fileobject._sock + self.assertTrue(httpresponse.__class__ is httplib.HTTPResponse) + fileobject = httpresponse.fp + self.assertTrue(fileobject.__class__ is socket._fileobject) + + self.assertTrue(not fileobject.closed) + response.close() + self.assertTrue(fileobject.closed) + +class OtherNetworkTests(unittest.TestCase): + def setUp(self): + if 0: # for debugging + import logging + logger = logging.getLogger("test_urllib2net") + logger.addHandler(logging.StreamHandler()) + + # XXX The rest of these tests aren't very good -- they don't check much. + # They do sometimes catch some major disasters, though. + + def test_ftp(self): + urls = [ + 'ftp://ftp.kernel.org/pub/linux/kernel/README', + 'ftp://ftp.kernel.org/pub/linux/kernel/non-existent-file', + #'ftp://ftp.kernel.org/pub/leenox/kernel/test', + 'ftp://gatekeeper.research.compaq.com/pub/DEC/SRC' + '/research-reports/00README-Legal-Rules-Regs', + ] + self._test_urls(urls, self._extra_handlers()) + + def test_file(self): + TESTFN = test_support.TESTFN + f = open(TESTFN, 'w') + try: + f.write('hi there\n') + f.close() + urls = [ + 'file:'+sanepathname2url(os.path.abspath(TESTFN)), + ('file:///nonsensename/etc/passwd', None, urllib2.URLError), + ] + self._test_urls(urls, self._extra_handlers(), retry=True) + finally: + os.remove(TESTFN) + + self.assertRaises(ValueError, urllib2.urlopen,'./relative_path/to/file') + + # XXX Following test depends on machine configurations that are internal + # to CNRI. Need to set up a public server with the right authentication + # configuration for test purposes. + +## def test_cnri(self): +## if socket.gethostname() == 'bitdiddle': +## localhost = 'bitdiddle.cnri.reston.va.us' +## elif socket.gethostname() == 'bitdiddle.concentric.net': +## localhost = 'localhost' +## else: +## localhost = None +## if localhost is not None: +## urls = [ +## 'file://%s/etc/passwd' % localhost, +## 'http://%s/simple/' % localhost, +## 'http://%s/digest/' % localhost, +## 'http://%s/not/found.h' % localhost, +## ] + +## bauth = HTTPBasicAuthHandler() +## bauth.add_password('basic_test_realm', localhost, 'jhylton', +## 'password') +## dauth = HTTPDigestAuthHandler() +## dauth.add_password('digest_test_realm', localhost, 'jhylton', +## 'password') + +## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) + + def test_urlwithfrag(self): + urlwith_frag = "https://docs.python.org/2/glossary.html#glossary" + with test_support.transient_internet(urlwith_frag): + req = urllib2.Request(urlwith_frag) + res = urllib2.urlopen(req) + self.assertEqual(res.geturl(), + "https://docs.python.org/2/glossary.html#glossary") + + def test_fileno(self): + req = urllib2.Request("http://www.python.org") + opener = urllib2.build_opener() + res = opener.open(req) + try: + res.fileno() + except AttributeError: + self.fail("HTTPResponse object should return a valid fileno") + finally: + res.close() + + def test_custom_headers(self): + url = "http://www.example.com" + with test_support.transient_internet(url): + opener = urllib2.build_opener() + request = urllib2.Request(url) + self.assertFalse(request.header_items()) + opener.open(request) + self.assertTrue(request.header_items()) + self.assertTrue(request.has_header('User-agent')) + request.add_header('User-Agent','Test-Agent') + opener.open(request) + self.assertEqual(request.get_header('User-agent'),'Test-Agent') + + def test_sites_no_connection_close(self): + # Some sites do not send Connection: close header. + # Verify that those work properly. (#issue12576) + + URL = 'http://www.imdb.com' # No Connection:close + with test_support.transient_internet(URL): + req = urllib2.urlopen(URL) + res = req.read() + self.assertTrue(res) + + def _test_urls(self, urls, handlers, retry=True): + import time + import logging + debug = logging.getLogger("test_urllib2").debug + + urlopen = urllib2.build_opener(*handlers).open + if retry: + urlopen = _wrap_with_retry_thrice(urlopen, urllib2.URLError) + + for url in urls: + if isinstance(url, tuple): + url, req, expected_err = url + else: + req = expected_err = None + with test_support.transient_internet(url): + debug(url) + try: + f = urlopen(url, req, TIMEOUT) + except EnvironmentError as err: + debug(err) + if expected_err: + msg = ("Didn't get expected error(s) %s for %s %s, got %s: %s" % + (expected_err, url, req, type(err), err)) + self.assertIsInstance(err, expected_err, msg) + except urllib2.URLError as err: + if isinstance(err[0], socket.timeout): + print >>sys.stderr, "" % url + continue + else: + raise + else: + try: + with test_support.transient_internet(url): + buf = f.read() + debug("read %d bytes" % len(buf)) + except socket.timeout: + print >>sys.stderr, "" % url + f.close() + debug("******** next url coming up...") + time.sleep(0.1) + + def _extra_handlers(self): + handlers = [] + + cfh = urllib2.CacheFTPHandler() + self.addCleanup(cfh.clear_cache) + cfh.setTimeout(1) + handlers.append(cfh) + + return handlers + + +class TimeoutTest(unittest.TestCase): + def test_http_basic(self): + self.assertTrue(socket.getdefaulttimeout() is None) + url = "http://www.python.org" + with test_support.transient_internet(url, timeout=None): + u = _urlopen_with_retry(url) + self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) + + def test_http_default_timeout(self): + self.assertTrue(socket.getdefaulttimeout() is None) + url = "http://www.python.org" + with test_support.transient_internet(url): + socket.setdefaulttimeout(60) + try: + u = _urlopen_with_retry(url) + finally: + socket.setdefaulttimeout(None) + self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 60) + + def test_http_no_timeout(self): + self.assertTrue(socket.getdefaulttimeout() is None) + url = "http://www.python.org" + with test_support.transient_internet(url): + socket.setdefaulttimeout(60) + try: + u = _urlopen_with_retry(url, timeout=None) + finally: + socket.setdefaulttimeout(None) + self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) + + def test_http_timeout(self): + url = "http://www.python.org" + with test_support.transient_internet(url): + u = _urlopen_with_retry(url, timeout=120) + self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120) + + FTP_HOST = "ftp://ftp.mirror.nl/pub/gnu/" + + def test_ftp_basic(self): + self.assertTrue(socket.getdefaulttimeout() is None) + with test_support.transient_internet(self.FTP_HOST, timeout=None): + u = _urlopen_with_retry(self.FTP_HOST) + self.assertTrue(u.fp.fp._sock.gettimeout() is None) + + def test_ftp_default_timeout(self): + self.assertTrue(socket.getdefaulttimeout() is None) + with test_support.transient_internet(self.FTP_HOST): + socket.setdefaulttimeout(60) + try: + u = _urlopen_with_retry(self.FTP_HOST) + finally: + socket.setdefaulttimeout(None) + self.assertEqual(u.fp.fp._sock.gettimeout(), 60) + + def test_ftp_no_timeout(self): + self.assertTrue(socket.getdefaulttimeout() is None) + with test_support.transient_internet(self.FTP_HOST): + socket.setdefaulttimeout(60) + try: + u = _urlopen_with_retry(self.FTP_HOST, timeout=None) + finally: + socket.setdefaulttimeout(None) + self.assertTrue(u.fp.fp._sock.gettimeout() is None) + + def test_ftp_timeout(self): + with test_support.transient_internet(self.FTP_HOST): + u = _urlopen_with_retry(self.FTP_HOST, timeout=60) + self.assertEqual(u.fp.fp._sock.gettimeout(), 60) + + +def test_main(): + test_support.requires("network") + test_support.run_unittest(AuthTests, + OtherNetworkTests, + CloseSocketTest, + TimeoutTest, + ) + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_urllibnet.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python + +import unittest +from test import test_support + +import socket +import urllib +import sys +import os +import time + +mimetools = test_support.import_module("mimetools", deprecated=True) + + +def _open_with_retry(func, host, *args, **kwargs): + # Connecting to remote hosts is flaky. Make it more robust + # by retrying the connection several times. + for i in range(3): + try: + return func(host, *args, **kwargs) + except IOError, last_exc: + continue + except: + raise + raise last_exc + + +class URLTimeoutTest(unittest.TestCase): + + TIMEOUT = 10.0 + + def setUp(self): + socket.setdefaulttimeout(self.TIMEOUT) + + def tearDown(self): + socket.setdefaulttimeout(None) + + def testURLread(self): + f = _open_with_retry(urllib.urlopen, "http://www.python.org/") + x = f.read() + +class urlopenNetworkTests(unittest.TestCase): + """Tests urllib.urlopen using the network. + + These tests are not exhaustive. Assuming that testing using files does a + good job overall of some of the basic interface features. There are no + tests exercising the optional 'data' and 'proxies' arguments. No tests + for transparent redirection have been written. + + setUp is not used for always constructing a connection to + http://www.python.org/ since there a few tests that don't use that address + and making a connection is expensive enough to warrant minimizing unneeded + connections. + + """ + + def urlopen(self, *args): + return _open_with_retry(urllib.urlopen, *args) + + def test_basic(self): + # Simple test expected to pass. + open_url = self.urlopen("http://www.python.org/") + for attr in ("read", "readline", "readlines", "fileno", "close", + "info", "geturl"): + self.assertTrue(hasattr(open_url, attr), "object returned from " + "urlopen lacks the %s attribute" % attr) + try: + self.assertTrue(open_url.read(), "calling 'read' failed") + finally: + open_url.close() + + def test_readlines(self): + # Test both readline and readlines. + open_url = self.urlopen("http://www.python.org/") + try: + self.assertIsInstance(open_url.readline(), basestring, + "readline did not return a string") + self.assertIsInstance(open_url.readlines(), list, + "readlines did not return a list") + finally: + open_url.close() + + def test_info(self): + # Test 'info'. + open_url = self.urlopen("http://www.python.org/") + try: + info_obj = open_url.info() + finally: + open_url.close() + self.assertIsInstance(info_obj, mimetools.Message, + "object returned by 'info' is not an " + "instance of mimetools.Message") + self.assertEqual(info_obj.getsubtype(), "html") + + def test_geturl(self): + # Make sure same URL as opened is returned by geturl. + # + # This test has been changed from what's currently in our + # lib-python/2.7 for Jython due to recent updates at the + # python.org to use https; other tests can take advantate of + # URL redirection + URL = "https://www.python.org/" + open_url = self.urlopen(URL) + try: + gotten_url = open_url.geturl() + finally: + open_url.close() + self.assertEqual(gotten_url, URL) + + def test_getcode(self): + # test getcode() with the fancy opener to get 404 error codes + URL = "http://www.python.org/XXXinvalidXXX" + open_url = urllib.FancyURLopener().open(URL) + try: + code = open_url.getcode() + finally: + open_url.close() + self.assertEqual(code, 404) + + @unittest.skipIf(test_support.is_jython, "Sockets cannot be used as file descriptors") + def test_fileno(self): + if (sys.platform in ('win32',) or + not hasattr(os, 'fdopen')): + # On Windows, socket handles are not file descriptors; this + # test can't pass on Windows. + return + # Make sure fd returned by fileno is valid. + open_url = self.urlopen("http://www.python.org/") + fd = open_url.fileno() + FILE = os.fdopen(fd) + try: + self.assertTrue(FILE.read(), "reading from file created using fd " + "returned by fileno failed") + finally: + FILE.close() + + def test_bad_address(self): + # Make sure proper exception is raised when connecting to a bogus + # address. + bogus_domain = "sadflkjsasf.i.nvali.d" + try: + socket.gethostbyname(bogus_domain) + except socket.gaierror: + pass + else: + # This happens with some overzealous DNS providers such as OpenDNS + self.skipTest("%r should not resolve for test to work" % bogus_domain) + self.assertRaises(IOError, + # SF patch 809915: In Sep 2003, VeriSign started + # highjacking invalid .com and .net addresses to + # boost traffic to their own site. This test + # started failing then. One hopes the .invalid + # domain will be spared to serve its defined + # purpose. + # urllib.urlopen, "http://www.sadflkjsasadf.com/") + urllib.urlopen, "http://sadflkjsasf.i.nvali.d/") + +class urlretrieveNetworkTests(unittest.TestCase): + """Tests urllib.urlretrieve using the network.""" + + def urlretrieve(self, *args): + return _open_with_retry(urllib.urlretrieve, *args) + + def test_basic(self): + # Test basic functionality. + file_location,info = self.urlretrieve("http://www.python.org/") + self.assertTrue(os.path.exists(file_location), "file location returned by" + " urlretrieve is not a valid path") + FILE = file(file_location) + try: + self.assertTrue(FILE.read(), "reading from the file location returned" + " by urlretrieve failed") + finally: + FILE.close() + os.unlink(file_location) + + def test_specified_path(self): + # Make sure that specifying the location of the file to write to works. + file_location,info = self.urlretrieve("http://www.python.org/", + test_support.TESTFN) + self.assertEqual(file_location, test_support.TESTFN) + self.assertTrue(os.path.exists(file_location)) + FILE = file(file_location) + try: + self.assertTrue(FILE.read(), "reading from temporary file failed") + finally: + FILE.close() + os.unlink(file_location) + + def test_header(self): + # Make sure header returned as 2nd value from urlretrieve is good. + file_location, header = self.urlretrieve("http://www.python.org/") + os.unlink(file_location) + self.assertIsInstance(header, mimetools.Message, + "header is not an instance of mimetools.Message") + + def test_data_header(self): + logo = "http://www.python.org/community/logos/python-logo-master-v3-TM.png" + file_location, fileheaders = self.urlretrieve(logo) + os.unlink(file_location) + datevalue = fileheaders.getheader('Date') + dateformat = '%a, %d %b %Y %H:%M:%S GMT' + try: + time.strptime(datevalue, dateformat) + except ValueError: + self.fail('Date value not in %r format', dateformat) + + + +def test_main(): + test_support.requires('network') + with test_support.check_py3k_warnings( + ("urllib.urlopen.. has been removed", DeprecationWarning)): + test_support.run_unittest(URLTimeoutTest, + urlopenNetworkTests, + urlretrieveNetworkTests) + +if __name__ == "__main__": + test_main() diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -1032,6 +1032,8 @@ + + @@ -1041,6 +1043,8 @@ + + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Jan 9 01:08:00 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 09 Jan 2015 00:08:00 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Dict_and_set_comps_no_longe?= =?utf-8?q?r_leak_iteration_variables?= Message-ID: <20150109000752.22419.65697@psf.io> https://hg.python.org/jython/rev/e270e881c84c changeset: 7521:e270e881c84c user: Jim Baker date: Thu Jan 08 16:55:51 2015 -0700 summary: Dict and set comps no longer leak iteration variables Dict and set comprehensions were acting like list comprehensions, in that their internal iteration variable was visible. Now they are hidden away, similar to a generator expression (and using the same internal logic in the compiler). files: Lib/test/test_dictcomps.py | 65 ---- Lib/test/test_setcomps.py | 154 ---------- src/org/python/compiler/CodeCompiler.java | 110 +++++-- src/org/python/compiler/ScopesCompiler.java | 52 +- 4 files changed, 106 insertions(+), 275 deletions(-) diff --git a/Lib/test/test_dictcomps.py b/Lib/test/test_dictcomps.py deleted file mode 100644 --- a/Lib/test/test_dictcomps.py +++ /dev/null @@ -1,65 +0,0 @@ - -doctests = """ - - # FIXME: Jython leaks dictcomp scope. - #>>> k = "old value" - #>>> a = {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None} - #>>> b = { k: None for k in range(10) } - #>>> a == b - #True - #>>> k - #'old value' - - >>> a = {0: 10, 1: 11, 2: 12, 3: 13, 4: 14, 5: 15, 6: 16, 7: 17, 8: 18, 9: 19} - >>> b = { k: k+10 for k in range(10) } - >>> a == b - True - - >>> g = "Global variable" - >>> a = {0: 'Global variable', 1: 'Global variable', 2: 'Global variable', 3: 'Global variable', 4: 'Global variable', 5: 'Global variable', 6: 'Global variable', 7: 'Global variable', 8: 'Global variable', 9: 'Global variable'} - >>> b = { k: g for k in range(10) } - >>> a == b - True - - >>> a = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} - >>> b = { k: v for k in range(10) for v in range(10) if k == v } - >>> a == b - True - - >>> a = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4, 38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6, 55: 6, 56: 6, 57: 6, 58: 6, 59: 6, 63: 7, 64: 7, 65: 7, 66: 7, 67: 7, 68: 7, 69: 7, 72: 8, 73: 8, 74: 8, 75: 8, 76: 8, 77: 8, 78: 8, 79: 8, 81: 9, 82: 9, 83: 9, 84: 9, 85: 9, 86: 9, 87: 9, 88: 9, 89: 9} - >>> b = { k: v for v in range(10) for k in range(v*9, v*10) } - >>> a == b - True - - >>> { x: y for y, x in ((1, 2), (3, 4)) } = 5 # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - SyntaxError: ... - - >>> { x: y for y, x in ((1, 2), (3, 4)) } += 5 # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - SyntaxError: ... - -""" - -__test__ = {'doctests' : doctests} - -def test_main(verbose=None): - import sys - from test import test_support - from test import test_dictcomps - test_support.run_doctest(test_dictcomps, verbose) - - # verify reference counting - if verbose and hasattr(sys, "gettotalrefcount"): - import gc - counts = [None] * 5 - for i in range(len(counts)): - test_support.run_doctest(test_dictcomps, verbose) - gc.collect() - counts[i] = sys.gettotalrefcount() - print(counts) - -if __name__ == "__main__": - test_main(verbose=True) diff --git a/Lib/test/test_setcomps.py b/Lib/test/test_setcomps.py deleted file mode 100644 --- a/Lib/test/test_setcomps.py +++ /dev/null @@ -1,154 +0,0 @@ -doctests = """ -########### Tests mostly copied from test_listcomps.py ############ - -Test simple loop with conditional - - >>> sum({i*i for i in range(100) if i&1 == 1}) - 166650 - -Test simple case - - >>> {2*y + x + 1 for x in (0,) for y in (1,)} - set([3]) - -Test simple nesting - - >>> list(sorted({(i,j) for i in range(3) for j in range(4)})) - [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] - -Test nesting with the inner expression dependent on the outer - - >>> list(sorted({(i,j) for i in range(4) for j in range(i)})) - [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] - -Make sure the induction variable is not exposed - - #FIXME: scope leaks in Jython. - #>>> i = 20 - #>>> sum({i*i for i in range(100)}) - #328350 - # - #>>> i - #20 - -Verify that syntax error's are raised for setcomps used as lvalues - - >>> {y for y in (1,2)} = 10 # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - SyntaxError: ... - - >>> {y for y in (1,2)} += 10 # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - SyntaxError: ... - - -Make a nested set comprehension that acts like set(range()) - - >>> def srange(n): - ... return {i for i in range(n)} - >>> list(sorted(srange(10))) - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - -Same again, only as a lambda expression instead of a function definition - - >>> lrange = lambda n: {i for i in range(n)} - >>> list(sorted(lrange(10))) - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - -Generators can call other generators: - - >>> def grange(n): - ... for x in {i for i in range(n)}: - ... yield x - >>> list(sorted(grange(5))) - [0, 1, 2, 3, 4] - - -Make sure that None is a valid return value - - >>> {None for i in range(10)} - set([None]) - -########### Tests for various scoping corner cases ############ - -Return lambdas that use the iteration variable as a default argument - - >>> items = {(lambda i=i: i) for i in range(5)} - >>> {x() for x in items} == set(range(5)) - True - -Same again, only this time as a closure variable - - >>> items = {(lambda: i) for i in range(5)} - >>> {x() for x in items} - set([4]) - -Another way to test that the iteration variable is local to the list comp - - #FIXME: scope leaks in Jython. - #>>> items = {(lambda: i) for i in range(5)} - #>>> i = 20 - #>>> {x() for x in items} - #set([4]) - -And confirm that a closure can jump over the list comp scope - - >>> items = {(lambda: y) for i in range(5)} - >>> y = 2 - >>> {x() for x in items} - set([2]) - -We also repeat each of the above scoping tests inside a function - - >>> def test_func(): - ... items = {(lambda i=i: i) for i in range(5)} - ... return {x() for x in items} - >>> test_func() == set(range(5)) - True - - >>> def test_func(): - ... items = {(lambda: i) for i in range(5)} - ... return {x() for x in items} - >>> test_func() - set([4]) - - #FIXME: scope leaks in Jython. - #>>> def test_func(): - #... items = {(lambda: i) for i in range(5)} - #... i = 20 - #... return {x() for x in items} - #>>> test_func() - #set([4]) - - >>> def test_func(): - ... items = {(lambda: y) for i in range(5)} - ... y = 2 - ... return {x() for x in items} - >>> test_func() - set([2]) - -""" - - -__test__ = {'doctests' : doctests} - -def test_main(verbose=None): - import sys - from test import test_support - from test import test_setcomps - test_support.run_doctest(test_setcomps, verbose) - - # verify reference counting - if verbose and hasattr(sys, "gettotalrefcount"): - import gc - counts = [None] * 5 - for i in range(len(counts)): - test_support.run_doctest(test_setcomps, verbose) - gc.collect() - counts[i] = sys.gettotalrefcount() - print(counts) - -if __name__ == "__main__": - test_main(verbose=True) diff --git a/src/org/python/compiler/CodeCompiler.java b/src/org/python/compiler/CodeCompiler.java --- a/src/org/python/compiler/CodeCompiler.java +++ b/src/org/python/compiler/CodeCompiler.java @@ -2176,53 +2176,30 @@ return null; } - @Override public Object visitSetComp(SetComp node) throws Exception { code.new_(p(PySet.class)); - code.dup(); - code.invokespecial(p(PySet.class), "", sig(Void.TYPE)); - - code.dup(); - - code.ldc("add"); - - code.invokevirtual(p(PyObject.class), "__getattr__", sig(PyObject.class, String.class)); - String tmp_append = "_{" + node.getLine() + "_" + node.getCharPositionInLine() + "}"; - - java.util.List args = new ArrayList(); - args.add(node.getInternalElt()); - - finishComp(node, args, node.getInternalGenerators(), tmp_append); - + visitInternalGenerators(node, node.getInternalElt(), node.getInternalGenerators()); + code.invokespecial(p(PySet.class), "", sig(Void.TYPE, PyObject.class)); return null; } @Override public Object visitDictComp(DictComp node) throws Exception { code.new_(p(PyDictionary.class)); - code.dup(); code.invokespecial(p(PyDictionary.class), "", sig(Void.TYPE)); - code.dup(); - - code.ldc("__setitem__"); - - code.invokevirtual(p(PyDictionary.class), "__getattr__", sig(PyObject.class, String.class)); - String tmp_append = "_{" + node.getLine() + "_" + node.getCharPositionInLine() + "}"; - - java.util.List args = new ArrayList(); - args.add(node.getInternalKey()); - args.add(node.getInternalValue()); - - finishComp(node, args, node.getInternalGenerators(), tmp_append); - + java.util.List kv = Arrays.asList(node.getInternalKey(), node.getInternalValue()); + visitInternalGenerators( + node, + new Tuple(node, kv, expr_contextType.UNDEFINED), + node.getInternalGenerators()); + code.invokevirtual(p(PyDictionary.class), "update", sig(Void.TYPE, PyObject.class)); return null; } - private void finishComp(expr node, java.util.List args, java.util.List generators, String tmp_append) throws Exception { set(new Name(node, tmp_append, expr_contextType.Store)); @@ -2586,6 +2563,77 @@ return null; } + private Object visitInternalGenerators(expr node, expr elt, java.util.List generators) + throws Exception { + String bound_exp = "_(x)"; + + setline(node); + + code.new_(p(PyFunction.class)); + code.dup(); + loadFrame(); + code.getfield(p(PyFrame.class), "f_globals", ci(PyObject.class)); + + ScopeInfo scope = module.getScopeInfo(node); + + int emptyArray = makeArray(new ArrayList()); + code.aload(emptyArray); + scope.setup_closure(); + scope.dump(); + + stmt n = new Expr(node, new Yield(node, elt)); + + expr iter = null; + for (int i = generators.size() - 1; i >= 0; i--) { + comprehension comp = generators.get(i); + for (int j = comp.getInternalIfs().size() - 1; j >= 0; j--) { + java.util.List bod = new ArrayList(); + bod.add(n); + n = new If(comp.getInternalIfs().get(j), comp.getInternalIfs().get(j), bod, + new ArrayList()); + } + java.util.List bod = new ArrayList(); + bod.add(n); + if (i != 0) { + n = new For(comp, comp.getInternalTarget(), comp.getInternalIter(), bod, + new ArrayList()); + } else { + n = new For(comp, comp.getInternalTarget(), new Name(node, bound_exp, + expr_contextType.Load), bod, new ArrayList()); + iter = comp.getInternalIter(); + } + } + + java.util.List bod = new ArrayList(); + bod.add(n); + module.codeConstant(new Suite(node, bod), "", true, + className, false, false, + node.getLine(), scope, cflags).get(code); + + code.aconst_null(); + if (!makeClosure(scope)) { + code.invokespecial(p(PyFunction.class), "", sig(Void.TYPE, PyObject.class, + PyObject[].class, PyCode.class, PyObject.class)); + } else { + code.invokespecial(p(PyFunction.class), "", sig(Void.TYPE, PyObject.class, + PyObject[].class, PyCode.class, PyObject.class, PyObject[].class)); + } + int genExp = storeTop(); + + visit(iter); + code.aload(genExp); + code.freeLocal(genExp); + code.swap(); + code.invokevirtual(p(PyObject.class), "__iter__", sig(PyObject.class)); + loadThreadState(); + code.swap(); + code.invokevirtual(p(PyObject.class), "__call__", + sig(PyObject.class, ThreadState.class, PyObject.class)); + freeArray(emptyArray); + + return null; + } + @Override public Object visitGeneratorExp(GeneratorExp node) throws Exception { String bound_exp = "_(x)"; diff --git a/src/org/python/compiler/ScopesCompiler.java b/src/org/python/compiler/ScopesCompiler.java --- a/src/org/python/compiler/ScopesCompiler.java +++ b/src/org/python/compiler/ScopesCompiler.java @@ -19,15 +19,18 @@ import org.python.antlr.ast.Name; import org.python.antlr.ast.Return; import org.python.antlr.ast.SetComp; +import org.python.antlr.ast.Tuple; import org.python.antlr.ast.With; import org.python.antlr.ast.Yield; import org.python.antlr.ast.arguments; +import org.python.antlr.ast.comprehension; import org.python.antlr.ast.expr_contextType; import org.python.antlr.base.expr; import org.python.antlr.base.stmt; import org.python.core.ParserFacade; import java.util.ArrayList; +import java.util.Arrays; import java.util.Hashtable; import java.util.Stack; import java.util.List; @@ -290,21 +293,15 @@ } @Override - public Object visitSetComp(SetComp node) throws Exception { - String tmp = "_{" + node.getLine() + "_" + node.getCharPositionInLine() - + "}"; - cur.addBound(tmp); - traverse(node); - return null; + public Object visitDictComp(DictComp node) throws Exception { + java.util.List kv = Arrays.asList(node.getInternalKey(), node.getInternalValue()); + return visitInternalGenerators( + node, new Tuple(node, kv, expr_contextType.UNDEFINED), node.getInternalGenerators()); } @Override - public Object visitDictComp(DictComp node) throws Exception { - String tmp = "_{" + node.getLine() + "_" + node.getCharPositionInLine() - + "}"; - cur.addBound(tmp); - traverse(node); - return null; + public Object visitSetComp(SetComp node) throws Exception { + return visitInternalGenerators(node, node.getInternalElt(), node.getInternalGenerators()); } @Override @@ -324,11 +321,11 @@ return null; } - @Override - public Object visitGeneratorExp(GeneratorExp node) throws Exception { + private Object visitInternalGenerators(expr node, expr elt, java.util.List generators) + throws Exception { // The first iterator is evaluated in the outer scope - if (node.getInternalGenerators() != null && node.getInternalGenerators().size() > 0) { - visit(node.getInternalGenerators().get(0).getInternalIter()); + if (generators != null && generators.size() > 0) { + visit(generators.get(0).getInternalIter()); } String bound_exp = "_(x)"; String tmp = "_(" + node.getLine() + "_" + node.getCharPositionInLine() @@ -345,23 +342,23 @@ cur.defineAsGenerator(node); cur.yield_count++; // The reset of the iterators are evaluated in the inner scope - if (node.getInternalElt() != null) { - visit(node.getInternalElt()); + if (elt != null) { + visit(elt); } - if (node.getInternalGenerators() != null) { - for (int i = 0; i < node.getInternalGenerators().size(); i++) { - if (node.getInternalGenerators().get(i) != null) { + if (generators != null) { + for (int i = 0; i < generators.size(); i++) { + if (generators.get(i) != null) { if (i == 0) { - visit(node.getInternalGenerators().get(i).getInternalTarget()); - if (node.getInternalGenerators().get(i).getInternalIfs() != null) { - for (expr cond : node.getInternalGenerators().get(i).getInternalIfs()) { + visit(generators.get(i).getInternalTarget()); + if (generators.get(i).getInternalIfs() != null) { + for (expr cond : generators.get(i).getInternalIfs()) { if (cond != null) { visit(cond); } } } } else { - visit(node.getInternalGenerators().get(i)); + visit(generators.get(i)); } } } @@ -372,6 +369,11 @@ } @Override + public Object visitGeneratorExp(GeneratorExp node) throws Exception { + return visitInternalGenerators(node, node.getInternalElt(), node.getInternalGenerators()); + } + + @Override public Object visitWith(With node) throws Exception { cur.max_with_count++; traverse(node); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Jan 9 05:15:51 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Fri, 09 Jan 2015 04:15:51 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7b4_for_chan?= =?utf-8?q?geset_e270e881c84c?= Message-ID: <20150109041539.8743.130@psf.io> https://hg.python.org/jython/rev/bfc775b6c48d changeset: 7522:bfc775b6c48d user: Frank Wierzbicki date: Fri Jan 09 04:15:39 2015 +0000 summary: Added tag v2.7b4 for changeset e270e881c84c files: .hgtags | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -82,3 +82,5 @@ 5e7462875b633e4f13b77985a1ed5186a0b92cac v2.7b3 744d673392b4bef667ed7d923e0a6c5abeec5d8a v2.7b3 6e650bf6302fbc142e9fa0397ac2e8f342e16aaf v2.7b4 +6e650bf6302fbc142e9fa0397ac2e8f342e16aaf v2.7b4 +e270e881c84cbe519035c215fde09677362a4953 v2.7b4 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Jan 9 23:20:06 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 09 Jan 2015 22:20:06 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_regrtest_to_support_-x_?= =?utf-8?q?to_exclude_tests?= Message-ID: <20150109221957.72575.67088@psf.io> https://hg.python.org/jython/rev/0d551095009f changeset: 7523:0d551095009f user: Jim Baker date: Fri Jan 09 15:17:56 2015 -0700 summary: Fix regrtest to support -x to exclude tests Fixes http://bugs.jython.org/issue2150 files: Lib/test/regrtest.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -360,7 +360,7 @@ tests = map(removepy, tests) stdtests = STDTESTS[:] - nottests = NOTTESTS.copy() + nottests = list(NOTTESTS.copy()) if exclude: for arg in args: if arg in stdtests: -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Jan 9 23:20:06 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 09 Jan 2015 22:20:06 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Make_select_and_socket_test?= =?utf-8?q?s_more_robust?= Message-ID: <20150109221957.125906.9319@psf.io> https://hg.python.org/jython/rev/68b3da7765c9 changeset: 7524:68b3da7765c9 user: Jim Baker date: Fri Jan 09 15:18:05 2015 -0700 summary: Make select and socket tests more robust Better handle TIME_WAIT issues when repeatedly reusing sockets in select and socket tests. Also parse java.net.SocketException for EADDRINUSE when used by a client socket to bind to a local socket. files: Lib/_socket.py | 39 ++++++++++++++++++++---- Lib/ssl.py | 8 +--- Lib/test/test_select.py | 10 ++++- Lib/test/test_select_new.py | 26 ++++++++++------ Lib/test/test_socket.py | 38 ++++++++++++++++++++--- Lib/test/test_support.py | 25 ++++++++++++++++ 6 files changed, 114 insertions(+), 32 deletions(-) diff --git a/Lib/_socket.py b/Lib/_socket.py --- a/Lib/_socket.py +++ b/Lib/_socket.py @@ -275,6 +275,8 @@ return _add_exception_attrs( error(errno.EAFNOSUPPORT, 'Address family not supported by protocol family: See http://wiki.python.org/jython/NewSocketModule#IPV6_address_support')) + if exc.message.startswith('Address already in use'): + return error(errno.EADDRINUSE, 'Address already in use') return _unmapped_exception(exc) @@ -546,7 +548,8 @@ result = self._handle_poll(partial(self.queue.poll, timeout_in_ns, TimeUnit.NANOSECONDS)) if result: return result - timeout = timeout - (time.time() - started) + timeout -= time.time() - started + log.debug("Spurious wakeup, retrying with timeout=%s", timeout, extra={"sock": "*"}) return [] @@ -764,7 +767,8 @@ elif self.timeout: self._handle_timeout(future.await, reason) if not future.isSuccess(): - log.exception("Got this failure %s during %s", future.cause(), reason, extra={"sock": self}) + log.debug("Got this failure %s during %s", future.cause(), reason, extra={"sock": self}) + print "Got this failure %s during %s (%s)" % (future.cause(), reason, self) raise future.cause() return future else: @@ -916,10 +920,10 @@ self.child_handler = ChildSocketHandler(self) b.childHandler(self.child_handler) - future = b.bind(self.bind_addr.getAddress(), self.bind_addr.getPort()) - self._handle_channel_future(future, "listen") + self.bind_future = b.bind(self.bind_addr.getAddress(), self.bind_addr.getPort()) + self._handle_channel_future(self.bind_future, "listen") self.bind_timestamp = time.time() - self.channel = future.channel() + self.channel = self.bind_future.channel() log.debug("Bound server socket to %s", self.bind_addr, extra={"sock": self}) def accept(self): @@ -1060,6 +1064,23 @@ else: return False + def _pending(self): + # Used by ssl.py for an undocumented function used in tests + # and of course some user code. Note that with Netty, + # readableBytes() in incoming or incoming_head are guaranteed + # to be plaintext because of the way pipelines work. However + # this is a terrible function to call because it's trying to + # do something synchronous in the async setting of sockets. + if self.socket_type == CLIENT_SOCKET or self.socket_type == DATAGRAM_SOCKET: + if self.incoming_head is not None: + pending = self.incoming_head.readableBytes() + else: + pending = 0 + for msg in self.incoming: + pending += msg.readableBytes() + return pending + return 0 + def _writable(self): return self.channel and self.channel.isActive() and self.channel.isWritable() @@ -1217,13 +1238,17 @@ while True: local_addr = self.channel.localAddress() if local_addr: - break + if hasattr(self, "bind_future"): + if self.bind_future.isDone(): + break + else: + break if time.time() - self.bind_timestamp > 1: # Presumably after a second something is completely wrong, # so punt raise error(errno.ENOTCONN, "Socket is not connected") log.debug("Poll for local address", extra={"sock": self}) - time.sleep(0.1) # completely arbitrary + time.sleep(0.01) # completely arbitrary if local_addr.getAddress().isAnyLocalAddress(): # Netty 4 will default to an IPv6 "any" address from a channel even if it was originally bound to an IPv4 "any" address # so, as a workaround, let's construct a new "any" address using the port information gathered above diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -26,8 +26,7 @@ SSL_ERROR_WANT_CONNECT, SSL_ERROR_EOF, SSL_ERROR_INVALID_ERROR_CODE, - error as socket_error, - CLIENT_SOCKET, DATAGRAM_SOCKET) + error as socket_error) from _sslcerts import _get_ssl_context from java.text import SimpleDateFormat @@ -204,10 +203,7 @@ def pending(self): # undocumented function, used by some tests # see also http://bugs.python.org/issue21430 - if self._sock.socket_type == CLIENT_SOCKET or self._sock.socket_type == DATAGRAM_SOCKET: - if self._sock.incoming_head is not None: - return self._sock.incoming_head.readableBytes() - return 0 + return self._sock._pending() def _readable(self): return self._sock._readable() diff --git a/Lib/test/test_select.py b/Lib/test/test_select.py --- a/Lib/test/test_select.py +++ b/Lib/test/test_select.py @@ -140,6 +140,7 @@ def testSocketRegisteredBeforeConnected(self): pass + @test_support.retry(Exception) def _testSocketRegisteredBeforeConnected(self): timeout = 1000 # milliseconds poll_object = select.poll() @@ -147,14 +148,14 @@ poll_object.register(self.cli, select.POLLOUT) result_list = poll_object.poll(timeout) result_sockets = [r[0] for r in result_list] - self.failUnless(self.cli in result_sockets, "Unconnected client socket should be selectable") + self.assertIn(self.cli, result_sockets, "Unconnected client socket should be selectable") # Now connect the socket, but DO NOT register it again self.cli.setblocking(0) self.cli.connect( (self.HOST, self.PORT) ) # Now poll again, to check that the poll object has recognised that the socket is now connected result_list = poll_object.poll(timeout) result_sockets = [r[0] for r in result_list] - self.failUnless(self.cli in result_sockets, "Connected client socket should have been selectable") + self.assertIn(self.cli, result_sockets, "Connected client socket should have been selectable") def testSelectOnSocketFileno(self): pass @@ -178,7 +179,10 @@ def test_main(): - tests = [TestSelectInvalidParameters, TestSelectClientSocket, TestPollClientSocket, ThreadedPollClientSocket, + tests = [TestSelectInvalidParameters, + TestSelectClientSocket, + TestPollClientSocket, + ThreadedPollClientSocket, TestJythonSelect] suites = [unittest.makeSuite(klass, 'test') for klass in tests] test_support._run_suite(unittest.TestSuite(suites)) diff --git a/Lib/test/test_select_new.py b/Lib/test/test_select_new.py --- a/Lib/test/test_select_new.py +++ b/Lib/test/test_select_new.py @@ -10,7 +10,7 @@ import socket import select -SERVER_ADDRESS = ("localhost", 54321) +SERVER_ADDRESS = ("localhost", 0) DATA_CHUNK_SIZE = 1000 DATA_CHUNK = "." * DATA_CHUNK_SIZE @@ -22,9 +22,7 @@ # The fundamental problem is that there is no reliable way to fill a socket with bytes # To address this for running on Netty, we arbitrarily send 10000 bytes -# zero select timeout fails these tests on cpython (on windows 2003 anyway); -# on Jython with Netty it will result in flaky test runs -SELECT_TIMEOUT = 0.001 +SELECT_TIMEOUT = 0 READ_TIMEOUT = 5 class AsynchronousServer: @@ -35,6 +33,7 @@ self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.server_socket.bind(SERVER_ADDRESS) self.server_socket.listen(5) + self.server_addr = self.server_socket.getsockname() try: self.server_socket.accept() except socket.error: @@ -142,16 +141,18 @@ class AsynchronousClient(AsynchronousHandler): - def __init__(self): + def __init__(self, server_addr): + self.server_addr = server_addr AsynchronousHandler.__init__(self, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) self.connected = 0 def start_connect(self): - result = self.socket.connect_ex(SERVER_ADDRESS) + result = self.socket.connect_ex(self.server_addr) if result == errno.EISCONN: self.connected = True else: - assert result == errno.EINPROGRESS + assert result == errno.EINPROGRESS, \ + "connect_ex returned %s (%s)" % (result, errno.errorcode.get(result, "Unknown errno")) def finish_connect(self): if self.connected: @@ -168,9 +169,10 @@ class TestSelectOnAccept(unittest.TestCase): def setUp(self): self.server = AsynchronousServer() - self.client = AsynchronousClient() + self.client = AsynchronousClient(self.server.server_addr) self.handler = None + @test_support.retry(Exception) def testSelectOnAccept(self): self.server.verify_not_acceptable() self.client.start_connect() @@ -186,9 +188,10 @@ self.server.close() class TestSelect(unittest.TestCase): + @test_support.retry(Exception) def setUp(self): self.server = AsynchronousServer() - self.client = AsynchronousClient() + self.client = AsynchronousClient(self.server.server_addr) self.client.start_connect() self.handler = self.server.accept() self.client.finish_connect() @@ -198,19 +201,21 @@ self.handler.close() self.server.close() + @test_support.retry(Exception) def testClientOut(self): self.client.verify_only_writable() self.handler.verify_only_writable() written = self.client.write() self.handler.verify_readable() - + self.handler.read(written/2) self.handler.verify_readable() self.handler.read(written/2) self.handler.verify_not_readable() + @test_support.retry(Exception) def testHandlerOut(self): written = self.handler.write() self.client.verify_readable() @@ -221,6 +226,7 @@ self.client.read(written/2) self.client.verify_not_readable() + @test_support.retry(Exception) def testBothOut(self): client_written = self.client.write() handler_written = self.handler.write() diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -111,7 +111,16 @@ it wants the client thread to proceed. This is useful if the server is about to execute a blocking routine that is dependent upon the client thread during its setup routine.""" - self.server_ready.set() + + def be_ready(): + # Because of socket reuse, old server sockets may still be + # accepting client connections as they get shutdown, but + # before they accept with the new server socket. + # + # Avoid race by ensuring accept is started before clients + # attempt to connect. + self.server_ready.set() + threading.Timer(0.1, be_ready).start() def _setUp(self): self.server_ready = threading.Event() @@ -1342,10 +1351,20 @@ def testNonBlockingConnect(self): # Testing non-blocking connect - conn, addr = self.serv.accept() + # this can potentially race with the client, so we need to loop + while True: + read, write, err = select.select([self.serv], [], [], 0.1) + if read or write or err: + break + if self.serv in read: + conn, addr = self.serv.accept() + conn.close() + else: + self.fail("Error trying to do accept after select: server socket was not in 'read'able list") def _testNonBlockingConnect(self): # Testing non-blocking connect + time.sleep(0.1) self.cli.setblocking(0) result = self.cli.connect_ex((self.HOST, self.PORT)) while True: @@ -1366,6 +1385,7 @@ def _testConnectWithLocalBind(self): # Testing blocking connect with local bind cli_port = self.PORT - 1 + start = time.time() while True: # Keep trying until a local port is available self.cli.settimeout(1) @@ -1378,12 +1398,17 @@ # previous test run). reset the client socket and try # again self.failUnlessEqual(se[0], errno.EADDRINUSE) + print "Got an error in connect, will retry", se try: self.cli.close() except socket.error: pass self.clientSetUp() cli_port -= 1 + # Make sure we have no tests currently holding open this socket + test_support.gc_collect() + if time.time() - start > 5: + self.fail("Timed out after 5 seconds") bound_host, bound_port = self.cli.getsockname() self.failUnlessEqual(bound_port, cli_port) @@ -1726,7 +1751,8 @@ self.failUnlessRaises(socket.timeout, raise_timeout, "TCP socket recv failed to generate a timeout exception (TCP)") - def estSendTimeout(self): + @unittest.skipIf(test_support.is_jython, "This test takes a very long time") + def testSendTimeout(self): def raise_timeout(*args, **kwargs): cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) cli_sock.connect( (self.HOST, self.PORT) ) @@ -1889,7 +1915,7 @@ # Maybe no IPv6 configured on the test machine. return ipv6_address_tuple = addrinfo[0][4] - self.failUnless (ipv6_address_tuple[0] in ["::1", "0:0:0:0:0:0:0:1"]) + self.assertIn(ipv6_address_tuple[0], ["::1", "0:0:0:0:0:0:0:1"]) self.failUnlessEqual(ipv6_address_tuple[1], 80) self.failUnlessEqual(ipv6_address_tuple[2], 0) # Can't have an expectation for scope @@ -1900,8 +1926,8 @@ self.failUnlessRaises(IndexError, lambda: ipv6_address_tuple[4]) # These str/repr tests may fail on some systems: the scope element of the tuple may be non-zero # In this case, we'll have to change the test to use .startswith() or .split() to exclude the scope element - self.failUnless(str(ipv6_address_tuple) in ["('::1', 80, 0, 0)", "('0:0:0:0:0:0:0:1', 80, 0, 0)"]) - self.failUnless(repr(ipv6_address_tuple) in ["('::1', 80, 0, 0)", "('0:0:0:0:0:0:0:1', 80, 0, 0)"]) + self.assertIn(str(ipv6_address_tuple), ["('::1', 80, 0, 0)", "('0:0:0:0:0:0:0:1', 80, 0, 0)"]) + self.assertIn(repr(ipv6_address_tuple), ["('::1', 80, 0, 0)", "('0:0:0:0:0:0:0:1', 80, 0, 0)"]) def testNonIntPort(self): hostname = "localhost" diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -1441,3 +1441,28 @@ """ stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip() return stderr + +def retry(exceptions, tries=6, delay=3, backoff=1.2): + # modified from https://wiki.python.org/moin/PythonDecoratorLibrary#Retry + def deco_retry(f): + + def wrapper(*args, **kwds): + mtries, mdelay = tries, delay + while mtries > 1: + try: + return f(*args, **kwds) + except exceptions as e: + print "Got %s, retrying in %.2f seconds..." % (str(e), mdelay) + # FIXME resource cleanup continues to be an issue + # in terms of tests we use from CPython. This only + # represents a bandaid - useful as it might be - + # and it should be revisited. + gc_collect() + time.sleep(mdelay) + mtries -= 1 + mdelay *= backoff + return f(*args, **kwds) + + return wrapper + + return deco_retry -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Jan 11 22:49:27 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 11 Jan 2015 21:49:27 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Minor_simplification_of_r75?= =?utf-8?q?23?= Message-ID: <20150111214924.125898.99893@psf.io> https://hg.python.org/jython/rev/7e9c491ffd0d changeset: 7525:7e9c491ffd0d user: Jim Baker date: Sun Jan 11 14:49:20 2015 -0700 summary: Minor simplification of r7523 Change regrtest -x to avoid extra copy of excluded tests, per suggestion of Arfrever on #jython files: Lib/test/regrtest.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -360,7 +360,7 @@ tests = map(removepy, tests) stdtests = STDTESTS[:] - nottests = list(NOTTESTS.copy()) + nottests = list(NOTTESTS) if exclude: for arg in args: if arg in stdtests: -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 12 07:43:32 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 12 Jan 2015 06:43:32 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Use_test=5Fdict_to_test_=5F?= =?utf-8?q?=5Fdict=5F=5F_of_objects_for_standard_methods?= Message-ID: <20150112064331.8757.36567@psf.io> https://hg.python.org/jython/rev/11923184dba0 changeset: 7526:11923184dba0 user: Jim Baker date: Sun Jan 11 23:42:17 2015 -0700 summary: Use test_dict to test __dict__ of objects for standard methods Partial fix for http://bugs.jython.org/issue1152612, however test_dict does not include testing of views. Such testing is in test_dictviews, but it is not designed for arbitrary dict implementations at this time. files: Lib/test/test_dict.py | 6 ++- Lib/test/test_dict_jy.py | 19 +++++++++- src/org/python/core/PyStringMap.java | 30 +++++++++++++-- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -328,9 +328,13 @@ y = self._make_dict({hashed1: 5}) if isinstance(y, Map) and not isinstance(y, ConcurrentMap): raise unittest.SkipTest("java.util.Map objects that do not implement ConcurrentMap have no concurrency guarantees") + # given that there are potentially multiple copies of the + # above dict in self._make_dict, record the hash_count so it + # can be subtracted out + setup_hash_count = hashed1.hash_count hashed2 = Hashed() y.setdefault(hashed2, []) - self.assertEqual(hashed1.hash_count, 1) + self.assertEqual(hashed1.hash_count, setup_hash_count) self.assertEqual(hashed2.hash_count, 1) self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1) diff --git a/Lib/test/test_dict_jy.py b/Lib/test/test_dict_jy.py --- a/Lib/test/test_dict_jy.py +++ b/Lib/test/test_dict_jy.py @@ -241,6 +241,22 @@ self.assertGreater({1L: 2L, 3L: 4L}, self._make_dict({1: 2})) +class PyStringMapTest(test_dict.DictTest): + # __dict__ for objects uses PyStringMap for historical reasons, so + # we have to test separately + + def _class(self, d): + # PyStringMap pretends to be a regular dict, so doing + # type(C().__dict__)() will not be helpful - it creates a + # regular dict. So explicitly create new objects and return + # their __dict__ + class C(object): + pass + newdict = C().__dict__ + newdict.update(d) + return newdict + + def test_main(): test_support.run_unittest( DictInitTest, @@ -248,7 +264,8 @@ DictMiscTest, DerivedDictTest, JavaIntegrationTest, - JavaDictTest) + JavaDictTest, + PyStringMapTest) if __name__ == '__main__': test_main() diff --git a/src/org/python/core/PyStringMap.java b/src/org/python/core/PyStringMap.java --- a/src/org/python/core/PyStringMap.java +++ b/src/org/python/core/PyStringMap.java @@ -12,6 +12,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.python.expose.ExposedClassMethod; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; @@ -33,6 +34,10 @@ private final ConcurrentMap table; + public ConcurrentMap getMap() { + return table; + } + public PyStringMap() { this(4); } @@ -71,6 +76,23 @@ return map; } + public static PyObject fromkeys(PyObject keys) { + return fromkeys(keys, Py.None); + } + + public static PyObject fromkeys(PyObject keys, PyObject value) { + return stringmap_fromkeys(TYPE, keys, value); + } + + @ExposedClassMethod(defaults = "Py.None", doc = BuiltinDocs.dict_fromkeys_doc) + static PyObject stringmap_fromkeys(PyType type, PyObject keys, PyObject value) { + PyObject d = type.__call__(); + for (PyObject o : keys.asIterable()) { + d.__setitem__(o, value); + } + return d; + } + @Override public int __len__() { return stringmap___len__(); @@ -105,7 +127,7 @@ public PyObject __getitem__(String key) { PyObject o = __finditem__(key); if (null == o) { - throw Py.KeyError("'" + key + "'"); + throw Py.KeyError(key); } else { return o; } @@ -123,7 +145,7 @@ } else { PyObject o = __finditem__(key); if (null == o) { - throw Py.KeyError("'" + key.toString() + "'"); + throw Py.KeyError(key); } else { return o; } @@ -185,7 +207,7 @@ } else { Object ret = table.remove(key); if (ret == null) { - throw Py.KeyError(key.toString()); + throw Py.KeyError(key); } } } @@ -493,7 +515,7 @@ PyObject value = table.remove(pyToKey(key)); if (value == null) { if (failobj == null) { - throw Py.KeyError(key.__repr__().toString()); + throw Py.KeyError(key); } else { return failobj; } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 12 19:24:35 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 12 Jan 2015 18:24:35 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_jycompile_Ant_task_prints_p?= =?utf-8?q?ath_of_lib_file_that_fails_to_compile?= Message-ID: <20150112182407.72569.97960@psf.io> https://hg.python.org/jython/rev/3e45b9f2bc2a changeset: 7527:3e45b9f2bc2a user: Jim Baker date: Mon Jan 12 11:24:03 2015 -0700 summary: jycompile Ant task prints path of lib file that fails to compile This should help find files that will not compile, and therefore break the ant build, usually due to isolated Unicode surrogate literals, as seen in evaluating what it will take to upgrade lib-python/2.7 to 2.7.9 (http://bugs.jython.org/issue2250) files: src/org/python/util/JycompileAntTask.java | 17 +++++++--- 1 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/org/python/util/JycompileAntTask.java b/src/org/python/util/JycompileAntTask.java --- a/src/org/python/util/JycompileAntTask.java +++ b/src/org/python/util/JycompileAntTask.java @@ -29,13 +29,18 @@ props.setProperty(PySystemState.PYTHON_CACHEDIR_SKIP, "true"); PySystemState.initialize(System.getProperties(), props); for (File src : toCompile) { - String name = _py_compile.getModuleName(src); - String compiledFilePath = name.replace('.', '/'); - if (src.getName().endsWith("__init__.py")) { - compiledFilePath += "/__init__"; + try { + String name = _py_compile.getModuleName(src); + String compiledFilePath = name.replace('.', '/'); + if (src.getName().endsWith("__init__.py")) { + compiledFilePath += "/__init__"; + } + File compiled = new File(destDir, compiledFilePath + "$py.class"); + compile(src, compiled, name); + } catch (RuntimeException e) { + log("Could not compile " + src); + throw e; } - File compiled = new File(destDir, compiledFilePath + "$py.class"); - compile(src, compiled, name); } } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 13 08:29:24 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 13 Jan 2015 07:29:24 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Initial_support_for_ensurep?= =?utf-8?q?ip_module?= Message-ID: <20150113072847.22403.40821@psf.io> https://hg.python.org/jython/rev/e7afa7fd1e5b changeset: 7528:e7afa7fd1e5b user: Jim Baker date: Tue Jan 13 00:28:38 2015 -0700 summary: Initial support for ensurepip module Copies over ensurepip backport from CPython 2.7.9. The main modification is that Jython needs modified wheels, with the wheels in wheels in Lib/ensurepip/_bundle built as follows: * setuptools from setuptools-11.3.1 release * pip from https://github.com/jythontools/pip To build wheels, build with ant using a clean release: 1. jython27 ez_setup.py 2. in checkout of https://github.com/jythontools/pip, jython27 setup.py install 3. in checkout of https://github.com/jythontools/wheel, jython27 setup.py install 4. copy output of jpip wheel of pip, setuptools into _bundle Rebuild Jython and validate with jython27 -m ensurepip. This should be automated! This new support needs to be further tested (and likely debugged) on Windows. Note that some of the tests in test_ensurepip are currently failing. files: CPythonLib.includes | 1 + Lib/ensurepip/__init__.py | 227 + Lib/ensurepip/_bundled/pip-1.6-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-11.3.1-py2.py3-none-any.whl | Bin Lib/test/test_support.py | 3 + lib-python/2.7/ensurepip/__init__.py | 227 + lib-python/2.7/ensurepip/__main__.py | 4 + lib-python/2.7/ensurepip/_uninstall.py | 30 + lib-python/2.7/test/_mock_backport.py | 2357 ++++++++++ lib-python/2.7/test/test_ensurepip.py | 352 + 10 files changed, 3201 insertions(+), 0 deletions(-) diff --git a/CPythonLib.includes b/CPythonLib.includes --- a/CPythonLib.includes +++ b/CPythonLib.includes @@ -6,6 +6,7 @@ distutils/** email/** encodings/** +ensurepip/** importlib/* logging/* test/** diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/ensurepip/__init__.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python2 +from __future__ import print_function + +import os +import os.path +import pkgutil +import shutil +import sys +import tempfile + + +__all__ = ["version", "bootstrap"] + + +_SETUPTOOLS_VERSION = "11.3.1" + +_PIP_VERSION = "1.6" + +# pip currently requires ssl support, so we try to provide a nicer +# error message when that is missing (http://bugs.python.org/issue19744) +_MISSING_SSL_MESSAGE = ("pip {} requires SSL/TLS".format(_PIP_VERSION)) +try: + import ssl +except ImportError: + ssl = None + + def _require_ssl_for_pip(): + raise RuntimeError(_MISSING_SSL_MESSAGE) +else: + def _require_ssl_for_pip(): + pass + +_PROJECTS = [ + ("setuptools", _SETUPTOOLS_VERSION), + ("pip", _PIP_VERSION), +] + + +def _run_pip(args, additional_paths=None): + # Add our bundled software to the sys.path so we can import it + if additional_paths is not None: + sys.path = additional_paths + sys.path + + # Install the bundled software + import pip + pip.main(args) + + +def version(): + """ + Returns a string specifying the bundled version of pip. + """ + return _PIP_VERSION + + +def _disable_pip_configuration_settings(): + # We deliberately ignore all pip environment variables + # when invoking pip + # See http://bugs.python.org/issue19734 for details + keys_to_remove = [k for k in os.environ if k.startswith("PIP_")] + for k in keys_to_remove: + del os.environ[k] + # We also ignore the settings in the default pip configuration file + # See http://bugs.python.org/issue20053 for details + os.environ['PIP_CONFIG_FILE'] = os.devnull + + +def bootstrap(root=None, upgrade=False, user=False, + altinstall=False, default_pip=True, + verbosity=0): + """ + Bootstrap pip into the current Python installation (or the given root + directory). + + Note that calling this function will alter both sys.path and os.environ. + """ + if altinstall and default_pip: + raise ValueError("Cannot use altinstall and default_pip together") + + _require_ssl_for_pip() + _disable_pip_configuration_settings() + + # By default, installing pip and setuptools installs all of the + # following scripts (X.Y == running Python version): + # + # pip, pipX, pipX.Y, easy_install, easy_install-X.Y + # + # pip 1.5+ allows ensurepip to request that some of those be left out + if altinstall: + # omit pip, pipX and easy_install + os.environ["ENSUREPIP_OPTIONS"] = "altinstall" + elif not default_pip: + # omit pip and easy_install + os.environ["ENSUREPIP_OPTIONS"] = "install" + + tmpdir = tempfile.mkdtemp() + try: + # Put our bundled wheels into a temporary directory and construct the + # additional paths that need added to sys.path + additional_paths = [] + for project, version in _PROJECTS: + wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version) + whl = pkgutil.get_data( + "ensurepip", + "_bundled/{}".format(wheel_name), + ) + with open(os.path.join(tmpdir, wheel_name), "wb") as fp: + fp.write(whl) + + additional_paths.append(os.path.join(tmpdir, wheel_name)) + + # Construct the arguments to be passed to the pip command + args = ["install", "--no-index", "--find-links", tmpdir] + if root: + args += ["--root", root] + if upgrade: + args += ["--upgrade"] + if user: + args += ["--user"] + if verbosity: + args += ["-" + "v" * verbosity] + + _run_pip(args + [p[0] for p in _PROJECTS], additional_paths) + finally: + shutil.rmtree(tmpdir, ignore_errors=True) + + +def _uninstall_helper(verbosity=0): + """Helper to support a clean default uninstall process on Windows + + Note that calling this function may alter os.environ. + """ + # Nothing to do if pip was never installed, or has been removed + try: + import pip + except ImportError: + return + + # If the pip version doesn't match the bundled one, leave it alone + if pip.__version__ != _PIP_VERSION: + msg = ("ensurepip will only uninstall a matching version " + "({!r} installed, {!r} bundled)") + print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr) + return + + _require_ssl_for_pip() + _disable_pip_configuration_settings() + + # Construct the arguments to be passed to the pip command + args = ["uninstall", "-y"] + if verbosity: + args += ["-" + "v" * verbosity] + + _run_pip(args + [p[0] for p in reversed(_PROJECTS)]) + + +def _main(argv=None): + if ssl is None: + print("Ignoring ensurepip failure: {}".format(_MISSING_SSL_MESSAGE), + file=sys.stderr) + return + + import argparse + parser = argparse.ArgumentParser(prog="python -m ensurepip") + parser.add_argument( + "--version", + action="version", + version="pip {}".format(version()), + help="Show the version of pip that is bundled with this Python.", + ) + parser.add_argument( + "-v", "--verbose", + action="count", + default=0, + dest="verbosity", + help=("Give more output. Option is additive, and can be used up to 3 " + "times."), + ) + parser.add_argument( + "-U", "--upgrade", + action="store_true", + default=False, + help="Upgrade pip and dependencies, even if already installed.", + ) + parser.add_argument( + "--user", + action="store_true", + default=False, + help="Install using the user scheme.", + ) + parser.add_argument( + "--root", + default=None, + help="Install everything relative to this alternate root directory.", + ) + parser.add_argument( + "--altinstall", + action="store_true", + default=False, + help=("Make an alternate install, installing only the X.Y versioned" + "scripts (Default: pipX, pipX.Y, easy_install-X.Y)"), + ) + parser.add_argument( + "--default-pip", + action="store_true", + default=True, + dest="default_pip", + help=argparse.SUPPRESS, + ) + parser.add_argument( + "--no-default-pip", + action="store_false", + dest="default_pip", + help=("Make a non default install, installing only the X and X.Y " + "versioned scripts."), + ) + + args = parser.parse_args(argv) + + bootstrap( + root=args.root, + upgrade=args.upgrade, + user=args.user, + verbosity=args.verbosity, + altinstall=args.altinstall, + default_pip=args.default_pip, + ) diff --git a/Lib/ensurepip/_bundled/pip-1.6-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-1.6-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..68605e592a267c90d057577ae34b1ba9fadaedd2 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-11.3.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-11.3.1-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6892ff89b4f916c40a0044c18d4b41dbf73340e3 GIT binary patch [stripped] diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -967,6 +967,9 @@ def captured_stdout(): return captured_output("stdout") +def captured_stderr(): + return captured_output("stderr") + def captured_stdin(): return captured_output("stdin") diff --git a/lib-python/2.7/ensurepip/__init__.py b/lib-python/2.7/ensurepip/__init__.py new file mode 100644 --- /dev/null +++ b/lib-python/2.7/ensurepip/__init__.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python2 +from __future__ import print_function + +import os +import os.path +import pkgutil +import shutil +import sys +import tempfile + + +__all__ = ["version", "bootstrap"] + + +_SETUPTOOLS_VERSION = "7.0" + +_PIP_VERSION = "1.5.6" + +# pip currently requires ssl support, so we try to provide a nicer +# error message when that is missing (http://bugs.python.org/issue19744) +_MISSING_SSL_MESSAGE = ("pip {} requires SSL/TLS".format(_PIP_VERSION)) +try: + import ssl +except ImportError: + ssl = None + + def _require_ssl_for_pip(): + raise RuntimeError(_MISSING_SSL_MESSAGE) +else: + def _require_ssl_for_pip(): + pass + +_PROJECTS = [ + ("setuptools", _SETUPTOOLS_VERSION), + ("pip", _PIP_VERSION), +] + + +def _run_pip(args, additional_paths=None): + # Add our bundled software to the sys.path so we can import it + if additional_paths is not None: + sys.path = additional_paths + sys.path + + # Install the bundled software + import pip + pip.main(args) + + +def version(): + """ + Returns a string specifying the bundled version of pip. + """ + return _PIP_VERSION + + +def _disable_pip_configuration_settings(): + # We deliberately ignore all pip environment variables + # when invoking pip + # See http://bugs.python.org/issue19734 for details + keys_to_remove = [k for k in os.environ if k.startswith("PIP_")] + for k in keys_to_remove: + del os.environ[k] + # We also ignore the settings in the default pip configuration file + # See http://bugs.python.org/issue20053 for details + os.environ['PIP_CONFIG_FILE'] = os.devnull + + +def bootstrap(root=None, upgrade=False, user=False, + altinstall=False, default_pip=True, + verbosity=0): + """ + Bootstrap pip into the current Python installation (or the given root + directory). + + Note that calling this function will alter both sys.path and os.environ. + """ + if altinstall and default_pip: + raise ValueError("Cannot use altinstall and default_pip together") + + _require_ssl_for_pip() + _disable_pip_configuration_settings() + + # By default, installing pip and setuptools installs all of the + # following scripts (X.Y == running Python version): + # + # pip, pipX, pipX.Y, easy_install, easy_install-X.Y + # + # pip 1.5+ allows ensurepip to request that some of those be left out + if altinstall: + # omit pip, pipX and easy_install + os.environ["ENSUREPIP_OPTIONS"] = "altinstall" + elif not default_pip: + # omit pip and easy_install + os.environ["ENSUREPIP_OPTIONS"] = "install" + + tmpdir = tempfile.mkdtemp() + try: + # Put our bundled wheels into a temporary directory and construct the + # additional paths that need added to sys.path + additional_paths = [] + for project, version in _PROJECTS: + wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version) + whl = pkgutil.get_data( + "ensurepip", + "_bundled/{}".format(wheel_name), + ) + with open(os.path.join(tmpdir, wheel_name), "wb") as fp: + fp.write(whl) + + additional_paths.append(os.path.join(tmpdir, wheel_name)) + + # Construct the arguments to be passed to the pip command + args = ["install", "--no-index", "--find-links", tmpdir] + if root: + args += ["--root", root] + if upgrade: + args += ["--upgrade"] + if user: + args += ["--user"] + if verbosity: + args += ["-" + "v" * verbosity] + + _run_pip(args + [p[0] for p in _PROJECTS], additional_paths) + finally: + shutil.rmtree(tmpdir, ignore_errors=True) + + +def _uninstall_helper(verbosity=0): + """Helper to support a clean default uninstall process on Windows + + Note that calling this function may alter os.environ. + """ + # Nothing to do if pip was never installed, or has been removed + try: + import pip + except ImportError: + return + + # If the pip version doesn't match the bundled one, leave it alone + if pip.__version__ != _PIP_VERSION: + msg = ("ensurepip will only uninstall a matching version " + "({!r} installed, {!r} bundled)") + print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr) + return + + _require_ssl_for_pip() + _disable_pip_configuration_settings() + + # Construct the arguments to be passed to the pip command + args = ["uninstall", "-y"] + if verbosity: + args += ["-" + "v" * verbosity] + + _run_pip(args + [p[0] for p in reversed(_PROJECTS)]) + + +def _main(argv=None): + if ssl is None: + print("Ignoring ensurepip failure: {}".format(_MISSING_SSL_MESSAGE), + file=sys.stderr) + return + + import argparse + parser = argparse.ArgumentParser(prog="python -m ensurepip") + parser.add_argument( + "--version", + action="version", + version="pip {}".format(version()), + help="Show the version of pip that is bundled with this Python.", + ) + parser.add_argument( + "-v", "--verbose", + action="count", + default=0, + dest="verbosity", + help=("Give more output. Option is additive, and can be used up to 3 " + "times."), + ) + parser.add_argument( + "-U", "--upgrade", + action="store_true", + default=False, + help="Upgrade pip and dependencies, even if already installed.", + ) + parser.add_argument( + "--user", + action="store_true", + default=False, + help="Install using the user scheme.", + ) + parser.add_argument( + "--root", + default=None, + help="Install everything relative to this alternate root directory.", + ) + parser.add_argument( + "--altinstall", + action="store_true", + default=False, + help=("Make an alternate install, installing only the X.Y versioned" + "scripts (Default: pipX, pipX.Y, easy_install-X.Y)"), + ) + parser.add_argument( + "--default-pip", + action="store_true", + default=True, + dest="default_pip", + help=argparse.SUPPRESS, + ) + parser.add_argument( + "--no-default-pip", + action="store_false", + dest="default_pip", + help=("Make a non default install, installing only the X and X.Y " + "versioned scripts."), + ) + + args = parser.parse_args(argv) + + bootstrap( + root=args.root, + upgrade=args.upgrade, + user=args.user, + verbosity=args.verbosity, + altinstall=args.altinstall, + default_pip=args.default_pip, + ) diff --git a/lib-python/2.7/ensurepip/__main__.py b/lib-python/2.7/ensurepip/__main__.py new file mode 100644 --- /dev/null +++ b/lib-python/2.7/ensurepip/__main__.py @@ -0,0 +1,4 @@ +import ensurepip + +if __name__ == "__main__": + ensurepip._main() diff --git a/lib-python/2.7/ensurepip/_uninstall.py b/lib-python/2.7/ensurepip/_uninstall.py new file mode 100644 --- /dev/null +++ b/lib-python/2.7/ensurepip/_uninstall.py @@ -0,0 +1,30 @@ +"""Basic pip uninstallation support, helper for the Windows uninstaller""" + +import argparse +import ensurepip + + +def _main(argv=None): + parser = argparse.ArgumentParser(prog="python -m ensurepip._uninstall") + parser.add_argument( + "--version", + action="version", + version="pip {}".format(ensurepip.version()), + help="Show the version of pip this will attempt to uninstall.", + ) + parser.add_argument( + "-v", "--verbose", + action="count", + default=0, + dest="verbosity", + help=("Give more output. Option is additive, and can be used up to 3 " + "times."), + ) + + args = parser.parse_args(argv) + + ensurepip._uninstall_helper(verbosity=args.verbosity) + + +if __name__ == "__main__": + _main() diff --git a/lib-python/2.7/test/_mock_backport.py b/lib-python/2.7/test/_mock_backport.py new file mode 100644 --- /dev/null +++ b/lib-python/2.7/test/_mock_backport.py @@ -0,0 +1,2357 @@ +# mock.py +# Test tools for mocking and patching. +# Maintained by Michael Foord +# Backport for other versions of Python available from +# http://pypi.python.org/pypi/mock + +__all__ = ( + 'Mock', + 'MagicMock', + 'patch', + 'sentinel', + 'DEFAULT', + 'ANY', + 'call', + 'create_autospec', + 'FILTER_DIR', + 'NonCallableMock', + 'NonCallableMagicMock', + 'mock_open', + 'PropertyMock', +) + + +__version__ = '1.0' + + +import inspect +import pprint +import sys + +from types import ModuleType +from functools import wraps, partial + + +_builtins = {name for name in __builtins__ if not name.startswith('_')} + +BaseExceptions = (BaseException,) +if 'java' in sys.platform: + # jython + import java + BaseExceptions = (BaseException, java.lang.Throwable) + + +FILTER_DIR = True + +# Workaround for issue #12370 +# Without this, the __class__ properties wouldn't be set correctly +_safe_super = super + +def _is_instance_mock(obj): + # can't use isinstance on Mock objects because they override __class__ + # The base class for all mocks is NonCallableMock + return issubclass(type(obj), NonCallableMock) + + +def _is_exception(obj): + return ( + isinstance(obj, BaseExceptions) or + isinstance(obj, type) and issubclass(obj, BaseExceptions) + ) + + +class _slotted(object): + __slots__ = ['a'] + + +DescriptorTypes = ( + type(_slotted.a), + property, +) + + +def _get_signature_object(func, as_instance, eat_self): + """ + Given an arbitrary, possibly callable object, try to create a suitable + signature object. + Return a (reduced func, signature) tuple, or None. + """ + if isinstance(func, type) and not as_instance: + # If it's a type and should be modelled as a type, use __init__. + try: + func = func.__init__ + except AttributeError: + return None + # Skip the `self` argument in __init__ + eat_self = True + elif not isinstance(func, FunctionTypes): + # If we really want to model an instance of the passed type, + # __call__ should be looked up, not __init__. + try: + func = func.__call__ + except AttributeError: + return None + if eat_self: + sig_func = partial(func, None) + else: + sig_func = func + try: + return func, inspect.signature(sig_func) + except ValueError: + # Certain callable types are not supported by inspect.signature() + return None + + +def _check_signature(func, mock, skipfirst, instance=False): + sig = _get_signature_object(func, instance, skipfirst) + if sig is None: + return + func, sig = sig + def checksig(_mock_self, *args, **kwargs): + sig.bind(*args, **kwargs) + _copy_func_details(func, checksig) + type(mock)._mock_check_sig = checksig + + +def _copy_func_details(func, funcopy): + funcopy.__name__ = func.__name__ + funcopy.__doc__ = func.__doc__ + try: + funcopy.__text_signature__ = func.__text_signature__ + except AttributeError: + pass + # we explicitly don't copy func.__dict__ into this copy as it would + # expose original attributes that should be mocked + try: + funcopy.__module__ = func.__module__ + except AttributeError: + pass + try: + funcopy.__defaults__ = func.__defaults__ + except AttributeError: + pass + try: + funcopy.__kwdefaults__ = func.__kwdefaults__ + except AttributeError: + pass + + +def _callable(obj): + if isinstance(obj, type): + return True + if getattr(obj, '__call__', None) is not None: + return True + return False + + +def _is_list(obj): + # checks for list or tuples + # XXXX badly named! + return type(obj) in (list, tuple) + + +def _instance_callable(obj): + """Given an object, return True if the object is callable. + For classes, return True if instances would be callable.""" + if not isinstance(obj, type): + # already an instance + return getattr(obj, '__call__', None) is not None + + # *could* be broken by a class overriding __mro__ or __dict__ via + # a metaclass + for base in (obj,) + obj.__mro__: + if base.__dict__.get('__call__') is not None: + return True + return False + + +# def _set_signature(mock, original, instance=False): +# # creates a function with signature (*args, **kwargs) that delegates to a +# # mock. It still does signature checking by calling a lambda with the same +# # signature as the original. +# if not _callable(original): +# return + +# skipfirst = isinstance(original, type) +# result = _get_signature_object(original, instance, skipfirst) +# if result is None: +# return +# func, sig = result +# def checksig(*args, **kwargs): +# sig.bind(*args, **kwargs) +# _copy_func_details(func, checksig) + +# name = original.__name__ +# if not name.isidentifier(): +# name = 'funcopy' +# context = {'_checksig_': checksig, 'mock': mock} +# src = """def %s(*args, **kwargs): +# _checksig_(*args, **kwargs) +# return mock(*args, **kwargs)""" % name +# exec (src, context) +# funcopy = context[name] +# _setup_func(funcopy, mock) +# return funcopy + + +def _setup_func(funcopy, mock): + funcopy.mock = mock + + # can't use isinstance with mocks + if not _is_instance_mock(mock): + return + + def assert_called_with(*args, **kwargs): + return mock.assert_called_with(*args, **kwargs) + def assert_called_once_with(*args, **kwargs): + return mock.assert_called_once_with(*args, **kwargs) + def assert_has_calls(*args, **kwargs): + return mock.assert_has_calls(*args, **kwargs) + def assert_any_call(*args, **kwargs): + return mock.assert_any_call(*args, **kwargs) + def reset_mock(): + funcopy.method_calls = _CallList() + funcopy.mock_calls = _CallList() + mock.reset_mock() + ret = funcopy.return_value + if _is_instance_mock(ret) and not ret is mock: + ret.reset_mock() + + funcopy.called = False + funcopy.call_count = 0 + funcopy.call_args = None + funcopy.call_args_list = _CallList() + funcopy.method_calls = _CallList() + funcopy.mock_calls = _CallList() + + funcopy.return_value = mock.return_value + funcopy.side_effect = mock.side_effect + funcopy._mock_children = mock._mock_children + + funcopy.assert_called_with = assert_called_with + funcopy.assert_called_once_with = assert_called_once_with + funcopy.assert_has_calls = assert_has_calls + funcopy.assert_any_call = assert_any_call + funcopy.reset_mock = reset_mock + + mock._mock_delegate = funcopy + + +def _is_magic(name): + return '__%s__' % name[2:-2] == name + + +class _SentinelObject(object): + "A unique, named, sentinel object." + def __init__(self, name): + self.name = name + + def __repr__(self): + return 'sentinel.%s' % self.name + + +class _Sentinel(object): + """Access attributes to return a named object, usable as a sentinel.""" + def __init__(self): + self._sentinels = {} + + def __getattr__(self, name): + if name == '__bases__': + # Without this help(unittest.mock) raises an exception + raise AttributeError + return self._sentinels.setdefault(name, _SentinelObject(name)) + + +sentinel = _Sentinel() + +DEFAULT = sentinel.DEFAULT +_missing = sentinel.MISSING +_deleted = sentinel.DELETED + + +def _copy(value): + if type(value) in (dict, list, tuple, set): + return type(value)(value) + return value + + +_allowed_names = set( + [ + 'return_value', '_mock_return_value', 'side_effect', + '_mock_side_effect', '_mock_parent', '_mock_new_parent', + '_mock_name', '_mock_new_name' + ] +) + + +def _delegating_property(name): + _allowed_names.add(name) + _the_name = '_mock_' + name + def _get(self, name=name, _the_name=_the_name): + sig = self._mock_delegate + if sig is None: + return getattr(self, _the_name) + return getattr(sig, name) + def _set(self, value, name=name, _the_name=_the_name): + sig = self._mock_delegate + if sig is None: + self.__dict__[_the_name] = value + else: + setattr(sig, name, value) + + return property(_get, _set) + + + +class _CallList(list): + + def __contains__(self, value): + if not isinstance(value, list): + return list.__contains__(self, value) + len_value = len(value) + len_self = len(self) + if len_value > len_self: + return False + + for i in range(0, len_self - len_value + 1): + sub_list = self[i:i+len_value] + if sub_list == value: + return True + return False + + def __repr__(self): + return pprint.pformat(list(self)) + + +def _check_and_set_parent(parent, value, name, new_name): + if not _is_instance_mock(value): + return False + if ((value._mock_name or value._mock_new_name) or + (value._mock_parent is not None) or + (value._mock_new_parent is not None)): + return False + + _parent = parent + while _parent is not None: + # setting a mock (value) as a child or return value of itself + # should not modify the mock + if _parent is value: + return False + _parent = _parent._mock_new_parent + + if new_name: + value._mock_new_parent = parent + value._mock_new_name = new_name + if name: + value._mock_parent = parent + value._mock_name = name + return True + +# Internal class to identify if we wrapped an iterator object or not. +class _MockIter(object): + def __init__(self, obj): + self.obj = iter(obj) + def __iter__(self): + return self + def __next__(self): + return next(self.obj) + +class Base(object): + _mock_return_value = DEFAULT + _mock_side_effect = None + def __init__(self, *args, **kwargs): + pass + + + +class NonCallableMock(Base): + """A non-callable version of `Mock`""" + + def __new__(cls, *args, **kw): + # every instance has its own class + # so we can create magic methods on the + # class without stomping on other mocks + new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__}) + instance = object.__new__(new) + return instance + + + def __init__( + self, spec=None, wraps=None, name=None, spec_set=None, + parent=None, _spec_state=None, _new_name='', _new_parent=None, + _spec_as_instance=False, _eat_self=None, unsafe=False, **kwargs + ): + if _new_parent is None: + _new_parent = parent + + __dict__ = self.__dict__ + __dict__['_mock_parent'] = parent + __dict__['_mock_name'] = name + __dict__['_mock_new_name'] = _new_name + __dict__['_mock_new_parent'] = _new_parent + + if spec_set is not None: + spec = spec_set + spec_set = True + if _eat_self is None: + _eat_self = parent is not None + + self._mock_add_spec(spec, spec_set, _spec_as_instance, _eat_self) + + __dict__['_mock_children'] = {} + __dict__['_mock_wraps'] = wraps + __dict__['_mock_delegate'] = None + + __dict__['_mock_called'] = False + __dict__['_mock_call_args'] = None + __dict__['_mock_call_count'] = 0 + __dict__['_mock_call_args_list'] = _CallList() + __dict__['_mock_mock_calls'] = _CallList() + + __dict__['method_calls'] = _CallList() + __dict__['_mock_unsafe'] = unsafe + + if kwargs: + self.configure_mock(**kwargs) + + _safe_super(NonCallableMock, self).__init__( + spec, wraps, name, spec_set, parent, + _spec_state + ) + + + def attach_mock(self, mock, attribute): + """ + Attach a mock as an attribute of this one, replacing its name and + parent. Calls to the attached mock will be recorded in the + `method_calls` and `mock_calls` attributes of this one.""" + mock._mock_parent = None + mock._mock_new_parent = None + mock._mock_name = '' + mock._mock_new_name = None + + setattr(self, attribute, mock) + + + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + + + def _mock_add_spec(self, spec, spec_set, _spec_as_instance=False, + _eat_self=False): + _spec_class = None + _spec_signature = None + + if spec is not None and not _is_list(spec): + if isinstance(spec, type): + _spec_class = spec + else: + _spec_class = _get_class(spec) + res = _get_signature_object(spec, + _spec_as_instance, _eat_self) + _spec_signature = res and res[1] + + spec = dir(spec) + + __dict__ = self.__dict__ + __dict__['_spec_class'] = _spec_class + __dict__['_spec_set'] = spec_set + __dict__['_spec_signature'] = _spec_signature + __dict__['_mock_methods'] = spec + + + def __get_return_value(self): + ret = self._mock_return_value + if self._mock_delegate is not None: + ret = self._mock_delegate.return_value + + if ret is DEFAULT: + ret = self._get_child_mock( + _new_parent=self, _new_name='()' + ) + self.return_value = ret + return ret + + + def __set_return_value(self, value): + if self._mock_delegate is not None: + self._mock_delegate.return_value = value + else: + self._mock_return_value = value + _check_and_set_parent(self, value, None, '()') + + __return_value_doc = "The value to be returned when the mock is called." + return_value = property(__get_return_value, __set_return_value, + __return_value_doc) + + + @property + def __class__(self): + if self._spec_class is None: + return type(self) + return self._spec_class + + called = _delegating_property('called') + call_count = _delegating_property('call_count') + call_args = _delegating_property('call_args') + call_args_list = _delegating_property('call_args_list') + mock_calls = _delegating_property('mock_calls') + + + def __get_side_effect(self): + delegated = self._mock_delegate + if delegated is None: + return self._mock_side_effect + sf = delegated.side_effect + if sf is not None and not callable(sf) and not isinstance(sf, _MockIter): + sf = _MockIter(sf) + delegated.side_effect = sf + return sf + + def __set_side_effect(self, value): + value = _try_iter(value) + delegated = self._mock_delegate + if delegated is None: + self._mock_side_effect = value + else: + delegated.side_effect = value + + side_effect = property(__get_side_effect, __set_side_effect) + + + def reset_mock(self): + "Restore the mock object to its initial state." + self.called = False + self.call_args = None + self.call_count = 0 + self.mock_calls = _CallList() + self.call_args_list = _CallList() + self.method_calls = _CallList() + + for child in self._mock_children.values(): + if isinstance(child, _SpecState): + continue + child.reset_mock() + + ret = self._mock_return_value + if _is_instance_mock(ret) and ret is not self: + ret.reset_mock() + + + def configure_mock(self, **kwargs): + """Set attributes on the mock through keyword arguments. + + Attributes plus return values and side effects can be set on child + mocks using standard dot notation and unpacking a dictionary in the + method call: + + >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> mock.configure_mock(**attrs)""" + for arg, val in sorted(kwargs.items(), + # we sort on the number of dots so that + # attributes are set before we set attributes on + # attributes + key=lambda entry: entry[0].count('.')): + args = arg.split('.') + final = args.pop() + obj = self + for entry in args: + obj = getattr(obj, entry) + setattr(obj, final, val) + + + def __getattr__(self, name): + if name in {'_mock_methods', '_mock_unsafe'}: + raise AttributeError(name) + elif self._mock_methods is not None: + if name not in self._mock_methods or name in _all_magics: + raise AttributeError("Mock object has no attribute %r" % name) + elif _is_magic(name): + raise AttributeError(name) + if not self._mock_unsafe: + if name.startswith(('assert', 'assret')): + raise AttributeError(name) + + result = self._mock_children.get(name) + if result is _deleted: + raise AttributeError(name) + elif result is None: + wraps = None + if self._mock_wraps is not None: + # XXXX should we get the attribute without triggering code + # execution? + wraps = getattr(self._mock_wraps, name) + + result = self._get_child_mock( + parent=self, name=name, wraps=wraps, _new_name=name, + _new_parent=self + ) + self._mock_children[name] = result + + elif isinstance(result, _SpecState): + result = create_autospec( + result.spec, result.spec_set, result.instance, + result.parent, result.name + ) + self._mock_children[name] = result + + return result + + + def __repr__(self): + _name_list = [self._mock_new_name] + _parent = self._mock_new_parent + last = self + + dot = '.' + if _name_list == ['()']: + dot = '' + seen = set() + while _parent is not None: + last = _parent + + _name_list.append(_parent._mock_new_name + dot) + dot = '.' + if _parent._mock_new_name == '()': + dot = '' + + _parent = _parent._mock_new_parent + + # use ids here so as not to call __hash__ on the mocks + if id(_parent) in seen: + break + seen.add(id(_parent)) + + _name_list = list(reversed(_name_list)) + _first = last._mock_name or 'mock' + if len(_name_list) > 1: + if _name_list[1] not in ('()', '().'): + _first += '.' + _name_list[0] = _first + name = ''.join(_name_list) + + name_string = '' + if name not in ('mock', 'mock.'): + name_string = ' name=%r' % name + + spec_string = '' + if self._spec_class is not None: + spec_string = ' spec=%r' + if self._spec_set: + spec_string = ' spec_set=%r' + spec_string = spec_string % self._spec_class.__name__ + return "<%s%s%s id='%s'>" % ( + type(self).__name__, + name_string, + spec_string, + id(self) + ) + + + def __dir__(self): + """Filter the output of `dir(mock)` to only useful members.""" + if not FILTER_DIR: + return object.__dir__(self) + + extras = self._mock_methods or [] + from_type = dir(type(self)) + from_dict = list(self.__dict__) + + from_type = [e for e in from_type if not e.startswith('_')] + from_dict = [e for e in from_dict if not e.startswith('_') or + _is_magic(e)] + return sorted(set(extras + from_type + from_dict + + list(self._mock_children))) + + + def __setattr__(self, name, value): + if name in _allowed_names: + # property setters go through here + return object.__setattr__(self, name, value) + elif (self._spec_set and self._mock_methods is not None and + name not in self._mock_methods and + name not in self.__dict__): + raise AttributeError("Mock object has no attribute '%s'" % name) + elif name in _unsupported_magics: + msg = 'Attempting to set unsupported magic method %r.' % name + raise AttributeError(msg) + elif name in _all_magics: + if self._mock_methods is not None and name not in self._mock_methods: + raise AttributeError("Mock object has no attribute '%s'" % name) + + if not _is_instance_mock(value): + setattr(type(self), name, _get_method(name, value)) + original = value + value = lambda *args, **kw: original(self, *args, **kw) + else: + # only set _new_name and not name so that mock_calls is tracked + # but not method calls + _check_and_set_parent(self, value, None, name) + setattr(type(self), name, value) + self._mock_children[name] = value + elif name == '__class__': + self._spec_class = value + return + else: + if _check_and_set_parent(self, value, name, name): + self._mock_children[name] = value + return object.__setattr__(self, name, value) + + + def __delattr__(self, name): + if name in _all_magics and name in type(self).__dict__: + delattr(type(self), name) + if name not in self.__dict__: + # for magic methods that are still MagicProxy objects and + # not set on the instance itself + return + + if name in self.__dict__: + object.__delattr__(self, name) + + obj = self._mock_children.get(name, _missing) + if obj is _deleted: + raise AttributeError(name) + if obj is not _missing: + del self._mock_children[name] + self._mock_children[name] = _deleted + + + def _format_mock_call_signature(self, args, kwargs): + name = self._mock_name or 'mock' + return _format_call_signature(name, args, kwargs) + + + def _format_mock_failure_message(self, args, kwargs): + message = 'Expected call: %s\nActual call: %s' + expected_string = self._format_mock_call_signature(args, kwargs) + call_args = self.call_args + if len(call_args) == 3: + call_args = call_args[1:] + actual_string = self._format_mock_call_signature(*call_args) + return message % (expected_string, actual_string) + + + def _call_matcher(self, _call): + """ + Given a call (or simply a (args, kwargs) tuple), return a + comparison key suitable for matching with other calls. + This is a best effort method which relies on the spec's signature, + if available, or falls back on the arguments themselves. + """ + sig = self._spec_signature + if sig is not None: + if len(_call) == 2: + name = '' + args, kwargs = _call + else: + name, args, kwargs = _call + try: + return name, sig.bind(*args, **kwargs) + except TypeError as e: + return e.with_traceback(None) + else: + return _call + + def assert_not_called(_mock_self): + """assert that the mock was never called. + """ + self = _mock_self + if self.call_count != 0: + msg = ("Expected '%s' to not have been called. Called %s times." % + (self._mock_name or 'mock', self.call_count)) + raise AssertionError(msg) + + def assert_called_with(_mock_self, *args, **kwargs): + """assert that the mock was called with the specified arguments. + + Raises an AssertionError if the args and keyword args passed in are + different to the last call to the mock.""" + self = _mock_self + if self.call_args is None: + expected = self._format_mock_call_signature(args, kwargs) + raise AssertionError('Expected call: %s\nNot called' % (expected,)) + + def _error_message(): + msg = self._format_mock_failure_message(args, kwargs) + return msg + expected = self._call_matcher((args, kwargs)) + actual = self._call_matcher(self.call_args) + if expected != actual: + raise AssertionError(_error_message()) + + + def assert_called_once_with(_mock_self, *args, **kwargs): + """assert that the mock was called exactly once and with the specified + arguments.""" + self = _mock_self + if not self.call_count == 1: + msg = ("Expected '%s' to be called once. Called %s times." % + (self._mock_name or 'mock', self.call_count)) + raise AssertionError(msg) + return self.assert_called_with(*args, **kwargs) + + + def assert_has_calls(self, calls, any_order=False): + """assert the mock has been called with the specified calls. + The `mock_calls` list is checked for the calls. + + If `any_order` is False (the default) then the calls must be + sequential. There can be extra calls before or after the + specified calls. + + If `any_order` is True then the calls can be in any order, but + they must all appear in `mock_calls`.""" + expected = [self._call_matcher(c) for c in calls] + all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls) + if not any_order: + if expected not in all_calls: + raise AssertionError( + 'Calls not found.\nExpected: %r\n' + 'Actual: %r' % (calls, self.mock_calls) + ) + return + + all_calls = list(all_calls) + + not_found = [] + for kall in expected: + try: + all_calls.remove(kall) + except ValueError: + not_found.append(kall) + if not_found: + raise AssertionError( + '%r not all found in call list' % (tuple(not_found),) + ) + + + def assert_any_call(self, *args, **kwargs): + """assert the mock has been called with the specified arguments. + + The assert passes if the mock has *ever* been called, unlike + `assert_called_with` and `assert_called_once_with` that only pass if + the call is the most recent one.""" + expected = self._call_matcher((args, kwargs)) + actual = [self._call_matcher(c) for c in self.call_args_list] + if expected not in actual: + expected_string = self._format_mock_call_signature(args, kwargs) + raise AssertionError( + '%s call not found' % expected_string + ) + + + def _get_child_mock(self, **kw): + """Create the child mocks for attributes and return value. + By default child mocks will be the same type as the parent. + Subclasses of Mock may want to override this to customize the way + child mocks are made. + + For non-callable mocks the callable variant will be used (rather than + any custom subclass).""" + _type = type(self) + if not issubclass(_type, CallableMixin): + if issubclass(_type, NonCallableMagicMock): + klass = MagicMock + elif issubclass(_type, NonCallableMock) : + klass = Mock + else: + klass = _type.__mro__[1] + return klass(**kw) + + + +def _try_iter(obj): + if obj is None: + return obj + if _is_exception(obj): + return obj + if _callable(obj): + return obj + try: + return iter(obj) + except TypeError: + # XXXX backwards compatibility + # but this will blow up on first call - so maybe we should fail early? + return obj + + + +class CallableMixin(Base): + + def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, + wraps=None, name=None, spec_set=None, parent=None, + _spec_state=None, _new_name='', _new_parent=None, **kwargs): + self.__dict__['_mock_return_value'] = return_value + + _safe_super(CallableMixin, self).__init__( + spec, wraps, name, spec_set, parent, + _spec_state, _new_name, _new_parent, **kwargs + ) + + self.side_effect = side_effect + + + def _mock_check_sig(self, *args, **kwargs): + # stub method that can be replaced with one with a specific signature + pass + + + def __call__(_mock_self, *args, **kwargs): + # can't use self in-case a function / method we are mocking uses self + # in the signature + _mock_self._mock_check_sig(*args, **kwargs) + return _mock_self._mock_call(*args, **kwargs) + + + def _mock_call(_mock_self, *args, **kwargs): + self = _mock_self + self.called = True + self.call_count += 1 + _new_name = self._mock_new_name + _new_parent = self._mock_new_parent + + _call = _Call((args, kwargs), two=True) + self.call_args = _call + self.call_args_list.append(_call) + self.mock_calls.append(_Call(('', args, kwargs))) + + seen = set() + skip_next_dot = _new_name == '()' + do_method_calls = self._mock_parent is not None + name = self._mock_name + while _new_parent is not None: + this_mock_call = _Call((_new_name, args, kwargs)) + if _new_parent._mock_new_name: + dot = '.' + if skip_next_dot: + dot = '' + + skip_next_dot = False + if _new_parent._mock_new_name == '()': + skip_next_dot = True + + _new_name = _new_parent._mock_new_name + dot + _new_name + + if do_method_calls: + if _new_name == name: + this_method_call = this_mock_call + else: + this_method_call = _Call((name, args, kwargs)) + _new_parent.method_calls.append(this_method_call) + + do_method_calls = _new_parent._mock_parent is not None + if do_method_calls: + name = _new_parent._mock_name + '.' + name + + _new_parent.mock_calls.append(this_mock_call) + _new_parent = _new_parent._mock_new_parent + + # use ids here so as not to call __hash__ on the mocks + _new_parent_id = id(_new_parent) + if _new_parent_id in seen: + break + seen.add(_new_parent_id) + + ret_val = DEFAULT + effect = self.side_effect + if effect is not None: + if _is_exception(effect): + raise effect + + if not _callable(effect): + result = next(effect) + if _is_exception(result): + raise result + if result is DEFAULT: + result = self.return_value + return result + + ret_val = effect(*args, **kwargs) + + if (self._mock_wraps is not None and + self._mock_return_value is DEFAULT): + return self._mock_wraps(*args, **kwargs) + if ret_val is DEFAULT: + ret_val = self.return_value + return ret_val + + + +class Mock(CallableMixin, NonCallableMock): + """ + Create a new `Mock` object. `Mock` takes several optional arguments + that specify the behaviour of the Mock object: + + * `spec`: This can be either a list of strings or an existing object (a + class or instance) that acts as the specification for the mock object. If + you pass in an object then a list of strings is formed by calling dir on + the object (excluding unsupported magic attributes and methods). Accessing + any attribute not in this list will raise an `AttributeError`. + + If `spec` is an object (rather than a list of strings) then + `mock.__class__` returns the class of the spec object. This allows mocks + to pass `isinstance` tests. + + * `spec_set`: A stricter variant of `spec`. If used, attempting to *set* + or get an attribute on the mock that isn't on the object passed as + `spec_set` will raise an `AttributeError`. + + * `side_effect`: A function to be called whenever the Mock is called. See + the `side_effect` attribute. Useful for raising exceptions or + dynamically changing return values. The function is called with the same + arguments as the mock, and unless it returns `DEFAULT`, the return + value of this function is used as the return value. + + If `side_effect` is an iterable then each call to the mock will return + the next value from the iterable. If any of the members of the iterable + are exceptions they will be raised instead of returned. + + * `return_value`: The value returned when the mock is called. By default + this is a new Mock (created on first access). See the + `return_value` attribute. + + * `wraps`: Item for the mock object to wrap. If `wraps` is not None then + calling the Mock will pass the call through to the wrapped object + (returning the real result). Attribute access on the mock will return a + Mock object that wraps the corresponding attribute of the wrapped object + (so attempting to access an attribute that doesn't exist will raise an + `AttributeError`). + + If the mock has an explicit `return_value` set then calls are not passed + to the wrapped object and the `return_value` is returned instead. + + * `name`: If the mock has a name then it will be used in the repr of the + mock. This can be useful for debugging. The name is propagated to child + mocks. + + Mocks can also be called with arbitrary keyword arguments. These will be + used to set attributes on the mock after it is created. + """ + + + +def _dot_lookup(thing, comp, import_path): + try: + return getattr(thing, comp) + except AttributeError: + __import__(import_path) + return getattr(thing, comp) + + +def _importer(target): + components = target.split('.') + import_path = components.pop(0) + thing = __import__(import_path) + + for comp in components: + import_path += ".%s" % comp + thing = _dot_lookup(thing, comp, import_path) + return thing + + +def _is_started(patcher): + # XXXX horrible + return hasattr(patcher, 'is_local') + + +class _patch(object): + + attribute_name = None + _active_patches = [] + + def __init__( + self, getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ): + if new_callable is not None: + if new is not DEFAULT: + raise ValueError( + "Cannot use 'new' and 'new_callable' together" + ) + if autospec is not None: + raise ValueError( + "Cannot use 'autospec' and 'new_callable' together" + ) + + self.getter = getter + self.attribute = attribute + self.new = new + self.new_callable = new_callable + self.spec = spec + self.create = create + self.has_local = False + self.spec_set = spec_set + self.autospec = autospec + self.kwargs = kwargs + self.additional_patchers = [] + + + def copy(self): + patcher = _patch( + self.getter, self.attribute, self.new, self.spec, + self.create, self.spec_set, + self.autospec, self.new_callable, self.kwargs + ) + patcher.attribute_name = self.attribute_name + patcher.additional_patchers = [ + p.copy() for p in self.additional_patchers + ] + return patcher + + + def __call__(self, func): + if isinstance(func, type): + return self.decorate_class(func) + return self.decorate_callable(func) + + + def decorate_class(self, klass): + for attr in dir(klass): + if not attr.startswith(patch.TEST_PREFIX): + continue + + attr_value = getattr(klass, attr) + if not hasattr(attr_value, "__call__"): + continue + + patcher = self.copy() + setattr(klass, attr, patcher(attr_value)) + return klass + + + def decorate_callable(self, func): + if hasattr(func, 'patchings'): + func.patchings.append(self) + return func + + @wraps(func) + def patched(*args, **keywargs): + extra_args = [] + entered_patchers = [] + + exc_info = tuple() + try: + for patching in patched.patchings: + arg = patching.__enter__() + entered_patchers.append(patching) + if patching.attribute_name is not None: + keywargs.update(arg) + elif patching.new is DEFAULT: + extra_args.append(arg) + + args += tuple(extra_args) + return func(*args, **keywargs) + except: + if (patching not in entered_patchers and + _is_started(patching)): + # the patcher may have been started, but an exception + # raised whilst entering one of its additional_patchers + entered_patchers.append(patching) + # Pass the exception to __exit__ + exc_info = sys.exc_info() + # re-raise the exception + raise + finally: + for patching in reversed(entered_patchers): + patching.__exit__(*exc_info) + + patched.patchings = [self] + return patched + + + def get_original(self): + target = self.getter() + name = self.attribute + + original = DEFAULT + local = False + + try: + original = target.__dict__[name] + except (AttributeError, KeyError): + original = getattr(target, name, DEFAULT) + else: + local = True + + if name in _builtins and isinstance(target, ModuleType): + self.create = True + + if not self.create and original is DEFAULT: + raise AttributeError( + "%s does not have the attribute %r" % (target, name) + ) + return original, local + + + def __enter__(self): + """Perform the patch.""" + new, spec, spec_set = self.new, self.spec, self.spec_set + autospec, kwargs = self.autospec, self.kwargs + new_callable = self.new_callable + self.target = self.getter() + + # normalise False to None + if spec is False: + spec = None + if spec_set is False: + spec_set = None + if autospec is False: + autospec = None + + if spec is not None and autospec is not None: + raise TypeError("Can't specify spec and autospec") + if ((spec is not None or autospec is not None) and + spec_set not in (True, None)): + raise TypeError("Can't provide explicit spec_set *and* spec or autospec") + + original, local = self.get_original() + + if new is DEFAULT and autospec is None: + inherit = False + if spec is True: + # set spec to the object we are replacing + spec = original + if spec_set is True: + spec_set = original + spec = None + elif spec is not None: + if spec_set is True: + spec_set = spec + spec = None + elif spec_set is True: + spec_set = original + + if spec is not None or spec_set is not None: + if original is DEFAULT: + raise TypeError("Can't use 'spec' with create=True") + if isinstance(original, type): + # If we're patching out a class and there is a spec + inherit = True + + Klass = MagicMock + _kwargs = {} + if new_callable is not None: + Klass = new_callable + elif spec is not None or spec_set is not None: + this_spec = spec + if spec_set is not None: + this_spec = spec_set + if _is_list(this_spec): + not_callable = '__call__' not in this_spec + else: + not_callable = not callable(this_spec) + if not_callable: + Klass = NonCallableMagicMock + + if spec is not None: + _kwargs['spec'] = spec + if spec_set is not None: + _kwargs['spec_set'] = spec_set + + # add a name to mocks + if (isinstance(Klass, type) and + issubclass(Klass, NonCallableMock) and self.attribute): + _kwargs['name'] = self.attribute + + _kwargs.update(kwargs) + new = Klass(**_kwargs) + + if inherit and _is_instance_mock(new): + # we can only tell if the instance should be callable if the + # spec is not a list + this_spec = spec + if spec_set is not None: + this_spec = spec_set + if (not _is_list(this_spec) and not + _instance_callable(this_spec)): + Klass = NonCallableMagicMock + + _kwargs.pop('name') + new.return_value = Klass(_new_parent=new, _new_name='()', + **_kwargs) + elif autospec is not None: + # spec is ignored, new *must* be default, spec_set is treated + # as a boolean. Should we check spec is not None and that spec_set + # is a bool? + if new is not DEFAULT: + raise TypeError( + "autospec creates the mock for you. Can't specify " + "autospec and new." + ) + if original is DEFAULT: + raise TypeError("Can't use 'autospec' with create=True") + spec_set = bool(spec_set) + if autospec is True: + autospec = original + + new = create_autospec(autospec, spec_set=spec_set, + _name=self.attribute, **kwargs) + elif kwargs: + # can't set keyword args when we aren't creating the mock + # XXXX If new is a Mock we could call new.configure_mock(**kwargs) + raise TypeError("Can't pass kwargs to a mock we aren't creating") + + new_attr = new + + self.temp_original = original + self.is_local = local + setattr(self.target, self.attribute, new_attr) + if self.attribute_name is not None: + extra_args = {} + if self.new is DEFAULT: + extra_args[self.attribute_name] = new + for patching in self.additional_patchers: + arg = patching.__enter__() + if patching.new is DEFAULT: + extra_args.update(arg) + return extra_args + + return new + + + def __exit__(self, *exc_info): + """Undo the patch.""" + if not _is_started(self): + raise RuntimeError('stop called on unstarted patcher') + + if self.is_local and self.temp_original is not DEFAULT: + setattr(self.target, self.attribute, self.temp_original) + else: + delattr(self.target, self.attribute) + if not self.create and not hasattr(self.target, self.attribute): + # needed for proxy objects like django settings + setattr(self.target, self.attribute, self.temp_original) + + del self.temp_original + del self.is_local + del self.target + for patcher in reversed(self.additional_patchers): + if _is_started(patcher): + patcher.__exit__(*exc_info) + + + def start(self): + """Activate a patch, returning any created mock.""" + result = self.__enter__() + self._active_patches.append(self) + return result + + + def stop(self): + """Stop an active patch.""" + try: + self._active_patches.remove(self) + except ValueError: + # If the patch hasn't been started this will fail + pass + + return self.__exit__() + + + +def _get_target(target): + try: + target, attribute = target.rsplit('.', 1) + except (TypeError, ValueError): + raise TypeError("Need a valid target to patch. You supplied: %r" % + (target,)) + getter = lambda: _importer(target) + return getter, attribute + + +def _patch_object( + target, attribute, new=DEFAULT, spec=None, + create=False, spec_set=None, autospec=None, + new_callable=None, **kwargs + ): + """ + patch the named member (`attribute`) on an object (`target`) with a mock + object. + + `patch.object` can be used as a decorator, class decorator or a context + manager. Arguments `new`, `spec`, `create`, `spec_set`, + `autospec` and `new_callable` have the same meaning as for `patch`. Like + `patch`, `patch.object` takes arbitrary keyword arguments for configuring + the mock object it creates. + + When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + """ + getter = lambda: target + return _patch( + getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ) + + +def _patch_multiple(target, spec=None, create=False, spec_set=None, + autospec=None, new_callable=None, **kwargs): + """Perform multiple patches in a single call. It takes the object to be + patched (either as an object or a string to fetch the object by importing) + and keyword arguments for the patches:: + + with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): + ... + + Use `DEFAULT` as the value if you want `patch.multiple` to create + mocks for you. In this case the created mocks are passed into a decorated + function by keyword, and a dictionary is returned when `patch.multiple` is + used as a context manager. + + `patch.multiple` can be used as a decorator, class decorator or a context + manager. The arguments `spec`, `spec_set`, `create`, + `autospec` and `new_callable` have the same meaning as for `patch`. These + arguments will be applied to *all* patches done by `patch.multiple`. + + When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + """ + if type(target) is str: + getter = lambda: _importer(target) + else: + getter = lambda: target + + if not kwargs: + raise ValueError( + 'Must supply at least one keyword argument with patch.multiple' + ) + # need to wrap in a list for python 3, where items is a view + items = list(kwargs.items()) + attribute, new = items[0] + patcher = _patch( + getter, attribute, new, spec, create, spec_set, + autospec, new_callable, {} + ) + patcher.attribute_name = attribute + for attribute, new in items[1:]: + this_patcher = _patch( + getter, attribute, new, spec, create, spec_set, + autospec, new_callable, {} + ) + this_patcher.attribute_name = attribute + patcher.additional_patchers.append(this_patcher) + return patcher + + +def patch( + target, new=DEFAULT, spec=None, create=False, + spec_set=None, autospec=None, new_callable=None, **kwargs + ): + """ + `patch` acts as a function decorator, class decorator or a context + manager. Inside the body of the function or with statement, the `target` + is patched with a `new` object. When the function/with statement exits + the patch is undone. + + If `new` is omitted, then the target is replaced with a + `MagicMock`. If `patch` is used as a decorator and `new` is + omitted, the created mock is passed in as an extra argument to the + decorated function. If `patch` is used as a context manager the created + mock is returned by the context manager. + + `target` should be a string in the form `'package.module.ClassName'`. The + `target` is imported and the specified object replaced with the `new` + object, so the `target` must be importable from the environment you are + calling `patch` from. The target is imported when the decorated function + is executed, not at decoration time. + + The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` + if patch is creating one for you. + + In addition you can pass `spec=True` or `spec_set=True`, which causes + patch to pass in the object being mocked as the spec/spec_set object. + + `new_callable` allows you to specify a different class, or callable object, + that will be called to create the `new` object. By default `MagicMock` is + used. + + A more powerful form of `spec` is `autospec`. If you set `autospec=True` + then the mock with be created with a spec from the object being replaced. + All attributes of the mock will also have the spec of the corresponding + attribute of the object being replaced. Methods and functions being + mocked will have their arguments checked and will raise a `TypeError` if + they are called with the wrong signature. For mocks replacing a class, + their return value (the 'instance') will have the same spec as the class. + + Instead of `autospec=True` you can pass `autospec=some_object` to use an + arbitrary object as the spec instead of the one being replaced. + + By default `patch` will fail to replace attributes that don't exist. If + you pass in `create=True`, and the attribute doesn't exist, patch will + create the attribute for you when the patched function is called, and + delete it again afterwards. This is useful for writing tests against + attributes that your production code creates at runtime. It is off by + default because it can be dangerous. With it switched on you can write + passing tests against APIs that don't actually exist! + + Patch can be used as a `TestCase` class decorator. It works by + decorating each test method in the class. This reduces the boilerplate + code when your test methods share a common patchings set. `patch` finds + tests by looking for method names that start with `patch.TEST_PREFIX`. + By default this is `test`, which matches the way `unittest` finds tests. + You can specify an alternative prefix by setting `patch.TEST_PREFIX`. + + Patch can be used as a context manager, with the with statement. Here the + patching applies to the indented block after the with statement. If you + use "as" then the patched object will be bound to the name after the + "as"; very useful if `patch` is creating a mock object for you. + + `patch` takes arbitrary keyword arguments. These will be passed to + the `Mock` (or `new_callable`) on construction. + + `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are + available for alternate use-cases. + """ + getter, attribute = _get_target(target) + return _patch( + getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ) + + +class _patch_dict(object): + """ + Patch a dictionary, or dictionary like object, and restore the dictionary + to its original state after the test. + + `in_dict` can be a dictionary or a mapping like container. If it is a + mapping then it must at least support getting, setting and deleting items + plus iterating over keys. + + `in_dict` can also be a string specifying the name of the dictionary, which + will then be fetched by importing it. + + `values` can be a dictionary of values to set in the dictionary. `values` + can also be an iterable of `(key, value)` pairs. + + If `clear` is True then the dictionary will be cleared before the new + values are set. + + `patch.dict` can also be called with arbitrary keyword arguments to set + values in the dictionary:: + + with patch.dict('sys.modules', mymodule=Mock(), other_module=Mock()): + ... + + `patch.dict` can be used as a context manager, decorator or class + decorator. When used as a class decorator `patch.dict` honours + `patch.TEST_PREFIX` for choosing which methods to wrap. + """ + + def __init__(self, in_dict, values=(), clear=False, **kwargs): + if isinstance(in_dict, str): + in_dict = _importer(in_dict) + self.in_dict = in_dict + # support any argument supported by dict(...) constructor + self.values = dict(values) + self.values.update(kwargs) + self.clear = clear + self._original = None + + + def __call__(self, f): + if isinstance(f, type): + return self.decorate_class(f) + @wraps(f) + def _inner(*args, **kw): + self._patch_dict() + try: + return f(*args, **kw) + finally: + self._unpatch_dict() + + return _inner + + + def decorate_class(self, klass): + for attr in dir(klass): + attr_value = getattr(klass, attr) + if (attr.startswith(patch.TEST_PREFIX) and + hasattr(attr_value, "__call__")): + decorator = _patch_dict(self.in_dict, self.values, self.clear) + decorated = decorator(attr_value) + setattr(klass, attr, decorated) + return klass + + + def __enter__(self): + """Patch the dict.""" + self._patch_dict() + + + def _patch_dict(self): + values = self.values + in_dict = self.in_dict + clear = self.clear + + try: + original = in_dict.copy() + except AttributeError: + # dict like object with no copy method + # must support iteration over keys + original = {} + for key in in_dict: + original[key] = in_dict[key] + self._original = original + + if clear: + _clear_dict(in_dict) + + try: + in_dict.update(values) + except AttributeError: + # dict like object with no update method + for key in values: + in_dict[key] = values[key] + + + def _unpatch_dict(self): + in_dict = self.in_dict + original = self._original + + _clear_dict(in_dict) + + try: + in_dict.update(original) + except AttributeError: + for key in original: + in_dict[key] = original[key] + + + def __exit__(self, *args): + """Unpatch the dict.""" + self._unpatch_dict() + return False + + start = __enter__ + stop = __exit__ + + +def _clear_dict(in_dict): + try: + in_dict.clear() + except AttributeError: + keys = list(in_dict) + for key in keys: + del in_dict[key] + + +def _patch_stopall(): + """Stop all active patches. LIFO to unroll nested patches.""" + for patch in reversed(_patch._active_patches): + patch.stop() + + +patch.object = _patch_object +patch.dict = _patch_dict +patch.multiple = _patch_multiple +patch.stopall = _patch_stopall +patch.TEST_PREFIX = 'test' + +magic_methods = ( + "lt le gt ge eq ne " + "getitem setitem delitem " + "len contains iter " + "hash str sizeof " + "enter exit " + "divmod neg pos abs invert " + "complex int float index " + "trunc floor ceil " + "bool next " +) + +numerics = ( + "add sub mul div floordiv mod lshift rshift and xor or pow truediv" +) +inplace = ' '.join('i%s' % n for n in numerics.split()) +right = ' '.join('r%s' % n for n in numerics.split()) + +# not including __prepare__, __instancecheck__, __subclasscheck__ +# (as they are metaclass methods) +# __del__ is not supported at all as it causes problems if it exists + +_non_defaults = set('__%s__' % method for method in [ + 'get', 'set', 'delete', 'reversed', 'missing', 'reduce', 'reduce_ex', + 'getinitargs', 'getnewargs', 'getstate', 'setstate', 'getformat', + 'setformat', 'repr', 'dir', 'subclasses', 'format', +]) + + +def _get_method(name, func): + "Turns a callable object (like a mock) into a real function" + def method(self, *args, **kw): + return func(self, *args, **kw) + method.__name__ = name + return method + + +_magics = set( + '__%s__' % method for method in + ' '.join([magic_methods, numerics, inplace, right]).split() +) + +_all_magics = _magics | _non_defaults + +_unsupported_magics = set([ + '__getattr__', '__setattr__', + '__init__', '__new__', '__prepare__' + '__instancecheck__', '__subclasscheck__', + '__del__' +]) + +_calculate_return_value = { + '__hash__': lambda self: object.__hash__(self), + '__str__': lambda self: object.__str__(self), + '__sizeof__': lambda self: object.__sizeof__(self), +} + +_return_values = { + '__lt__': NotImplemented, + '__gt__': NotImplemented, + '__le__': NotImplemented, + '__ge__': NotImplemented, + '__int__': 1, + '__contains__': False, + '__len__': 0, + '__exit__': False, + '__complex__': 1j, + '__float__': 1.0, + '__bool__': True, + '__index__': 1, +} + + +def _get_eq(self): + def __eq__(other): + ret_val = self.__eq__._mock_return_value + if ret_val is not DEFAULT: + return ret_val + return self is other + return __eq__ + +def _get_ne(self): + def __ne__(other): + if self.__ne__._mock_return_value is not DEFAULT: + return DEFAULT + return self is not other + return __ne__ + +def _get_iter(self): + def __iter__(): + ret_val = self.__iter__._mock_return_value + if ret_val is DEFAULT: + return iter([]) + # if ret_val was already an iterator, then calling iter on it should + # return the iterator unchanged + return iter(ret_val) + return __iter__ + +_side_effect_methods = { + '__eq__': _get_eq, + '__ne__': _get_ne, + '__iter__': _get_iter, +} + + + +def _set_return_value(mock, method, name): + fixed = _return_values.get(name, DEFAULT) + if fixed is not DEFAULT: + method.return_value = fixed + return + + return_calulator = _calculate_return_value.get(name) + if return_calulator is not None: + try: + return_value = return_calulator(mock) + except AttributeError: + # XXXX why do we return AttributeError here? + # set it as a side_effect instead? + return_value = AttributeError(name) + method.return_value = return_value + return + + side_effector = _side_effect_methods.get(name) + if side_effector is not None: + method.side_effect = side_effector(mock) + + + +class MagicMixin(object): + def __init__(self, *args, **kw): + _safe_super(MagicMixin, self).__init__(*args, **kw) + self._mock_set_magics() + + + def _mock_set_magics(self): + these_magics = _magics + + if self._mock_methods is not None: + these_magics = _magics.intersection(self._mock_methods) + + remove_magics = set() + remove_magics = _magics - these_magics + + for entry in remove_magics: + if entry in type(self).__dict__: + # remove unneeded magic methods + delattr(self, entry) + + # don't overwrite existing attributes if called a second time + these_magics = these_magics - set(type(self).__dict__) + + _type = type(self) + for entry in these_magics: + setattr(_type, entry, MagicProxy(entry, self)) + + + +class NonCallableMagicMock(MagicMixin, NonCallableMock): + """A version of `MagicMock` that isn't callable.""" + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + self._mock_set_magics() + + + +class MagicMock(MagicMixin, Mock): + """ + MagicMock is a subclass of Mock with default implementations + of most of the magic methods. You can use MagicMock without having to + configure the magic methods yourself. + + If you use the `spec` or `spec_set` arguments then *only* magic + methods that exist in the spec will be created. + + Attributes and the return value of a `MagicMock` will also be `MagicMocks`. + """ + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + self._mock_set_magics() + + + +class MagicProxy(object): + def __init__(self, name, parent): + self.name = name + self.parent = parent + + def __call__(self, *args, **kwargs): + m = self.create_mock() + return m(*args, **kwargs) + + def create_mock(self): + entry = self.name + parent = self.parent + m = parent._get_child_mock(name=entry, _new_name=entry, + _new_parent=parent) + setattr(parent, entry, m) + _set_return_value(parent, m, entry) + return m + + def __get__(self, obj, _type=None): + return self.create_mock() + + + +class _ANY(object): + "A helper object that compares equal to everything." + + __hash__ = object.__hash__ + + def __eq__(self, other): + return True + + def __ne__(self, other): + return False + + def __repr__(self): + return '' + +ANY = _ANY() + + + +def _format_call_signature(name, args, kwargs): + message = '%s(%%s)' % name + formatted_args = '' + args_string = ', '.join([repr(arg) for arg in args]) + kwargs_string = ', '.join([ + '%s=%r' % (key, value) for key, value in sorted(kwargs.items()) + ]) + if args_string: + formatted_args = args_string + if kwargs_string: + if formatted_args: + formatted_args += ', ' + formatted_args += kwargs_string + + return message % formatted_args + + + +class _Call(tuple): + """ + A tuple for holding the results of a call to a mock, either in the form + `(args, kwargs)` or `(name, args, kwargs)`. + + If args or kwargs are empty then a call tuple will compare equal to + a tuple without those values. This makes comparisons less verbose:: + + _Call(('name', (), {})) == ('name',) + _Call(('name', (1,), {})) == ('name', (1,)) + _Call(((), {'a': 'b'})) == ({'a': 'b'},) + + The `_Call` object provides a useful shortcut for comparing with call:: + + _Call(((1, 2), {'a': 3})) == call(1, 2, a=3) + _Call(('foo', (1, 2), {'a': 3})) == call.foo(1, 2, a=3) + + If the _Call has no name then it will match any name. + """ + + __hash__ = object.__hash__ + + def __new__(cls, value=(), name=None, parent=None, two=False, + from_kall=True): + name = '' + args = () + kwargs = {} + _len = len(value) + if _len == 3: + name, args, kwargs = value + elif _len == 2: + first, second = value + if isinstance(first, str): + name = first + if isinstance(second, tuple): + args = second + else: + kwargs = second + else: + args, kwargs = first, second + elif _len == 1: + value, = value + if isinstance(value, str): + name = value + elif isinstance(value, tuple): + args = value + else: + kwargs = value + + if two: + return tuple.__new__(cls, (args, kwargs)) + + return tuple.__new__(cls, (name, args, kwargs)) + + + def __init__(self, value=(), name=None, parent=None, two=False, + from_kall=True): + self.name = name + self.parent = parent + self.from_kall = from_kall + + + def __eq__(self, other): + if other is ANY: + return True + try: + len_other = len(other) + except TypeError: + return False + + self_name = '' + if len(self) == 2: + self_args, self_kwargs = self + else: + self_name, self_args, self_kwargs = self + + other_name = '' + if len_other == 0: + other_args, other_kwargs = (), {} + elif len_other == 3: + other_name, other_args, other_kwargs = other + elif len_other == 1: + value, = other + if isinstance(value, tuple): + other_args = value + other_kwargs = {} + elif isinstance(value, str): + other_name = value + other_args, other_kwargs = (), {} + else: + other_args = () + other_kwargs = value + else: + # len 2 + # could be (name, args) or (name, kwargs) or (args, kwargs) + first, second = other + if isinstance(first, str): + other_name = first + if isinstance(second, tuple): + other_args, other_kwargs = second, {} + else: + other_args, other_kwargs = (), second + else: + other_args, other_kwargs = first, second + + if self_name and other_name != self_name: + return False + + # this order is important for ANY to work! + return (other_args, other_kwargs) == (self_args, self_kwargs) + + + def __ne__(self, other): + return not self.__eq__(other) + + + def __call__(self, *args, **kwargs): + if self.name is None: + return _Call(('', args, kwargs), name='()') + + name = self.name + '()' + return _Call((self.name, args, kwargs), name=name, parent=self) + + + def __getattr__(self, attr): + if self.name is None: + return _Call(name=attr, from_kall=False) + name = '%s.%s' % (self.name, attr) + return _Call(name=name, parent=self, from_kall=False) + + + def count(self, *args, **kwargs): + return self.__getattr__('count')(*args, **kwargs) + + def index(self, *args, **kwargs): + return self.__getattr__('index')(*args, **kwargs) + + def __repr__(self): + if not self.from_kall: + name = self.name or 'call' + if name.startswith('()'): + name = 'call%s' % name + return name + + if len(self) == 2: + name = 'call' + args, kwargs = self + else: + name, args, kwargs = self + if not name: + name = 'call' + elif not name.startswith('()'): + name = 'call.%s' % name + else: + name = 'call%s' % name + return _format_call_signature(name, args, kwargs) + + + def call_list(self): + """For a call object that represents multiple calls, `call_list` + returns a list of all the intermediate calls as well as the + final call.""" + vals = [] + thing = self + while thing is not None: + if thing.from_kall: + vals.append(thing) + thing = thing.parent + return _CallList(reversed(vals)) + + +call = _Call(from_kall=False) + + + +def create_autospec(spec, spec_set=False, instance=False, _parent=None, + _name=None, **kwargs): + """Create a mock object using another object as a spec. Attributes on the + mock will use the corresponding attribute on the `spec` object as their + spec. + + Functions or methods being mocked will have their arguments checked + to check that they are called with the correct signature. + + If `spec_set` is True then attempting to set attributes that don't exist + on the spec object will raise an `AttributeError`. + + If a class is used as a spec then the return value of the mock (the + instance of the class) will have the same spec. You can use a class as the + spec for an instance object by passing `instance=True`. The returned mock + will only be callable if instances of the mock are callable. + + `create_autospec` also takes arbitrary keyword arguments that are passed to + the constructor of the created mock.""" + if _is_list(spec): + # can't pass a list instance to the mock constructor as it will be + # interpreted as a list of strings + spec = type(spec) + + is_type = isinstance(spec, type) + + _kwargs = {'spec': spec} + if spec_set: + _kwargs = {'spec_set': spec} + elif spec is None: + # None we mock with a normal mock without a spec + _kwargs = {} + if _kwargs and instance: + _kwargs['_spec_as_instance'] = True + + _kwargs.update(kwargs) + + Klass = MagicMock + if type(spec) in DescriptorTypes: + # descriptors don't have a spec + # because we don't know what type they return + _kwargs = {} + elif not _callable(spec): + Klass = NonCallableMagicMock + elif is_type and instance and not _instance_callable(spec): + Klass = NonCallableMagicMock + + _name = _kwargs.pop('name', _name) + + _new_name = _name + if _parent is None: + # for a top level object no _new_name should be set + _new_name = '' + + mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name, + name=_name, **_kwargs) + + if isinstance(spec, FunctionTypes): + # should only happen at the top level because we don't + # recurse for functions + mock = _set_signature(mock, spec) + else: + _check_signature(spec, mock, is_type, instance) + + if _parent is not None and not instance: + _parent._mock_children[_name] = mock + + if is_type and not instance and 'return_value' not in kwargs: + mock.return_value = create_autospec(spec, spec_set, instance=True, + _name='()', _parent=mock) + + for entry in dir(spec): + if _is_magic(entry): + # MagicMock already does the useful magic methods for us + continue + + # XXXX do we need a better way of getting attributes without + # triggering code execution (?) Probably not - we need the actual + # object to mock it so we would rather trigger a property than mock + # the property descriptor. Likewise we want to mock out dynamically + # provided attributes. + # XXXX what about attributes that raise exceptions other than + # AttributeError on being fetched? + # we could be resilient against it, or catch and propagate the + # exception when the attribute is fetched from the mock + try: + original = getattr(spec, entry) + except AttributeError: + continue + + kwargs = {'spec': original} + if spec_set: + kwargs = {'spec_set': original} + + if not isinstance(original, FunctionTypes): + new = _SpecState(original, spec_set, mock, entry, instance) + mock._mock_children[entry] = new + else: + parent = mock + if isinstance(spec, FunctionTypes): + parent = mock.mock + + skipfirst = _must_skip(spec, entry, is_type) + kwargs['_eat_self'] = skipfirst + new = MagicMock(parent=parent, name=entry, _new_name=entry, + _new_parent=parent, + **kwargs) + mock._mock_children[entry] = new + _check_signature(original, new, skipfirst=skipfirst) + + # so functions created with _set_signature become instance attributes, + # *plus* their underlying mock exists in _mock_children of the parent + # mock. Adding to _mock_children may be unnecessary where we are also + # setting as an instance attribute? + if isinstance(new, FunctionTypes): + setattr(mock, entry, new) + + return mock + + +def _must_skip(spec, entry, is_type): + """ + Return whether we should skip the first argument on spec's `entry` + attribute. + """ + if not isinstance(spec, type): + if entry in getattr(spec, '__dict__', {}): + # instance attribute - shouldn't skip + return False + spec = spec.__class__ + + for klass in spec.__mro__: + result = klass.__dict__.get(entry, DEFAULT) + if result is DEFAULT: + continue + if isinstance(result, (staticmethod, classmethod)): + return False + elif isinstance(getattr(result, '__get__', None), MethodWrapperTypes): + # Normal method => skip if looked up on type + # (if looked up on instance, self is already skipped) + return is_type + else: + return False + + # shouldn't get here unless function is a dynamically provided attribute + # XXXX untested behaviour + return is_type + + +def _get_class(obj): + try: + return obj.__class__ + except AttributeError: + # it is possible for objects to have no __class__ + return type(obj) + + +class _SpecState(object): + + def __init__(self, spec, spec_set=False, parent=None, + name=None, ids=None, instance=False): + self.spec = spec + self.ids = ids + self.spec_set = spec_set + self.parent = parent + self.instance = instance + self.name = name + + +FunctionTypes = ( + # python function + type(create_autospec), + # instance method + type(ANY.__eq__), +) + +MethodWrapperTypes = ( + type(ANY.__eq__.__get__), +) + + +file_spec = None + +def _iterate_read_data(read_data): + # Helper for mock_open: + # Retrieve lines from read_data via a generator so that separate calls to + # readline, read, and readlines are properly interleaved + data_as_list = ['{}\n'.format(l) for l in read_data.split('\n')] + + if data_as_list[-1] == '\n': + # If the last line ended in a newline, the list comprehension will have an + # extra entry that's just a newline. Remove this. + data_as_list = data_as_list[:-1] + else: + # If there wasn't an extra newline by itself, then the file being + # emulated doesn't have a newline to end the last line remove the + # newline that our naive format() added + data_as_list[-1] = data_as_list[-1][:-1] + + for line in data_as_list: + yield line + +def mock_open(mock=None, read_data=''): + """ + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` methoddline`, and `readlines` of the + file handle to return. This is an empty string by default. + """ + def _readlines_side_effect(*args, **kwargs): + if handle.readlines.return_value is not None: + return handle.readlines.return_value + return list(_data) + + def _read_side_effect(*args, **kwargs): + if handle.read.return_value is not None: + return handle.read.return_value + return ''.join(_data) + + def _readline_side_effect(): + if handle.readline.return_value is not None: + while True: + yield handle.readline.return_value + for line in _data: + yield line + + + global file_spec + if file_spec is None: + import _io + file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) + + if mock is None: + mock = MagicMock(name='open', spec=open) + + handle = MagicMock(spec=file_spec) + handle.__enter__.return_value = handle + + _data = _iterate_read_data(read_data) + + handle.write.return_value = None + handle.read.return_value = None + handle.readline.return_value = None + handle.readlines.return_value = None + + handle.read.side_effect = _read_side_effect + handle.readline.side_effect = _readline_side_effect() + handle.readlines.side_effect = _readlines_side_effect + + mock.return_value = handle + return mock + + +class PropertyMock(Mock): + """ + A mock intended to be used as a property, or other descriptor, on a class. + `PropertyMock` provides `__get__` and `__set__` methods so you can specify + a return value when it is fetched. + + Fetching a `PropertyMock` instance from an object calls the mock, with + no args. Setting it calls the mock with the value being set. + """ + def _get_child_mock(self, **kwargs): + return MagicMock(**kwargs) + + def __get__(self, obj, obj_type): + return self() + def __set__(self, obj, val): + self(val) diff --git a/lib-python/2.7/test/test_ensurepip.py b/lib-python/2.7/test/test_ensurepip.py new file mode 100644 --- /dev/null +++ b/lib-python/2.7/test/test_ensurepip.py @@ -0,0 +1,352 @@ +import unittest +import os +import os.path +import contextlib +import sys +import test._mock_backport as mock +import test.test_support + +import ensurepip +import ensurepip._uninstall + +# pip currently requires ssl support, so we ensure we handle +# it being missing (http://bugs.python.org/issue19744) +ensurepip_no_ssl = test.test_support.import_fresh_module("ensurepip", + blocked=["ssl"]) +try: + import ssl +except ImportError: + ssl = None + + def requires_usable_pip(f): + deco = unittest.skip(ensurepip._MISSING_SSL_MESSAGE) + return deco(f) +else: + def requires_usable_pip(f): + return f + + +class TestEnsurePipVersion(unittest.TestCase): + + def test_returns_version(self): + self.assertEqual(ensurepip._PIP_VERSION, ensurepip.version()) + + +class EnsurepipMixin: + + def setUp(self): + run_pip_patch = mock.patch("ensurepip._run_pip") + self.run_pip = run_pip_patch.start() + self.addCleanup(run_pip_patch.stop) + + # Avoid side effects on the actual os module + real_devnull = os.devnull + os_patch = mock.patch("ensurepip.os") + patched_os = os_patch.start() + self.addCleanup(os_patch.stop) + patched_os.devnull = real_devnull + patched_os.path = os.path + self.os_environ = patched_os.environ = os.environ.copy() + + +class TestBootstrap(EnsurepipMixin, unittest.TestCase): + + @requires_usable_pip + def test_basic_bootstrapping(self): + ensurepip.bootstrap() + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "setuptools", "pip", + ], + mock.ANY, + ) + + additional_paths = self.run_pip.call_args[0][1] + self.assertEqual(len(additional_paths), 2) + + @requires_usable_pip + def test_bootstrapping_with_root(self): + ensurepip.bootstrap(root="/foo/bar/") + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "--root", "/foo/bar/", + "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_user(self): + ensurepip.bootstrap(user=True) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "--user", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_upgrade(self): + ensurepip.bootstrap(upgrade=True) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "--upgrade", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_verbosity_1(self): + ensurepip.bootstrap(verbosity=1) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "-v", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_verbosity_2(self): + ensurepip.bootstrap(verbosity=2) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "-vv", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_verbosity_3(self): + ensurepip.bootstrap(verbosity=3) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "-vvv", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_regular_install(self): + ensurepip.bootstrap() + self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "install") + + @requires_usable_pip + def test_bootstrapping_with_alt_install(self): + ensurepip.bootstrap(altinstall=True) + self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "altinstall") + + @requires_usable_pip + def test_bootstrapping_with_default_pip(self): + ensurepip.bootstrap(default_pip=True) + self.assertNotIn("ENSUREPIP_OPTIONS", self.os_environ) + + def test_altinstall_default_pip_conflict(self): + with self.assertRaises(ValueError): + ensurepip.bootstrap(altinstall=True, default_pip=True) + self.assertFalse(self.run_pip.called) + + @requires_usable_pip + def test_pip_environment_variables_removed(self): + # ensurepip deliberately ignores all pip environment variables + # See http://bugs.python.org/issue19734 for details + self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder" + ensurepip.bootstrap() + self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ) + + @requires_usable_pip + def test_pip_config_file_disabled(self): + # ensurepip deliberately ignores the pip config file + # See http://bugs.python.org/issue20053 for details + ensurepip.bootstrap() + self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull) + + + at contextlib.contextmanager +def fake_pip(version=ensurepip._PIP_VERSION): + if version is None: + pip = None + else: + class FakePip(): + __version__ = version + pip = FakePip() + sentinel = object() + orig_pip = sys.modules.get("pip", sentinel) + sys.modules["pip"] = pip + try: + yield pip + finally: + if orig_pip is sentinel: + del sys.modules["pip"] + else: + sys.modules["pip"] = orig_pip + + +class TestUninstall(EnsurepipMixin, unittest.TestCase): + + def test_uninstall_skipped_when_not_installed(self): + with fake_pip(None): + ensurepip._uninstall_helper() + self.assertFalse(self.run_pip.called) + + def test_uninstall_skipped_with_warning_for_wrong_version(self): + with fake_pip("not a valid version"): + with test.test_support.captured_stderr() as stderr: + ensurepip._uninstall_helper() + warning = stderr.getvalue().strip() + self.assertIn("only uninstall a matching version", warning) + self.assertFalse(self.run_pip.called) + + @requires_usable_pip + def test_uninstall(self): + with fake_pip(): + ensurepip._uninstall_helper() + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "pip", "setuptools"] + ) + + @requires_usable_pip + def test_uninstall_with_verbosity_1(self): + with fake_pip(): + ensurepip._uninstall_helper(verbosity=1) + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "-v", "pip", "setuptools"] + ) + + @requires_usable_pip + def test_uninstall_with_verbosity_2(self): + with fake_pip(): + ensurepip._uninstall_helper(verbosity=2) + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "-vv", "pip", "setuptools"] + ) + + @requires_usable_pip + def test_uninstall_with_verbosity_3(self): + with fake_pip(): + ensurepip._uninstall_helper(verbosity=3) + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "-vvv", "pip", "setuptools"] + ) + + @requires_usable_pip + def test_pip_environment_variables_removed(self): + # ensurepip deliberately ignores all pip environment variables + # See http://bugs.python.org/issue19734 for details + self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder" + with fake_pip(): + ensurepip._uninstall_helper() + self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ) + + @requires_usable_pip + def test_pip_config_file_disabled(self): + # ensurepip deliberately ignores the pip config file + # See http://bugs.python.org/issue20053 for details + with fake_pip(): + ensurepip._uninstall_helper() + self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull) + + +class TestMissingSSL(EnsurepipMixin, unittest.TestCase): + + def setUp(self): + sys.modules["ensurepip"] = ensurepip_no_ssl + + @self.addCleanup + def restore_module(): + sys.modules["ensurepip"] = ensurepip + super(TestMissingSSL, self).setUp() + + def test_bootstrap_requires_ssl(self): + self.os_environ["PIP_THIS_SHOULD_STAY"] = "test fodder" + with self.assertRaisesRegexp(RuntimeError, "requires SSL/TLS"): + ensurepip_no_ssl.bootstrap() + self.assertFalse(self.run_pip.called) + self.assertIn("PIP_THIS_SHOULD_STAY", self.os_environ) + + def test_uninstall_requires_ssl(self): + self.os_environ["PIP_THIS_SHOULD_STAY"] = "test fodder" + with self.assertRaisesRegexp(RuntimeError, "requires SSL/TLS"): + with fake_pip(): + ensurepip_no_ssl._uninstall_helper() + self.assertFalse(self.run_pip.called) + self.assertIn("PIP_THIS_SHOULD_STAY", self.os_environ) + + def test_main_exits_early_with_warning(self): + with test.test_support.captured_stderr() as stderr: + ensurepip_no_ssl._main(["--version"]) + warning = stderr.getvalue().strip() + self.assertTrue(warning.endswith("requires SSL/TLS"), warning) + self.assertFalse(self.run_pip.called) + +# Basic testing of the main functions and their argument parsing + +EXPECTED_VERSION_OUTPUT = "pip " + ensurepip._PIP_VERSION + + +class TestBootstrappingMainFunction(EnsurepipMixin, unittest.TestCase): + + @requires_usable_pip + def test_bootstrap_version(self): + with test.test_support.captured_stderr() as stderr: + with self.assertRaises(SystemExit): + ensurepip._main(["--version"]) + result = stderr.getvalue().strip() + self.assertEqual(result, EXPECTED_VERSION_OUTPUT) + self.assertFalse(self.run_pip.called) + + @requires_usable_pip + def test_basic_bootstrapping(self): + ensurepip._main([]) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "setuptools", "pip", + ], + mock.ANY, + ) + + additional_paths = self.run_pip.call_args[0][1] + self.assertEqual(len(additional_paths), 2) + + +class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase): + + def test_uninstall_version(self): + with test.test_support.captured_stderr() as stderr: + with self.assertRaises(SystemExit): + ensurepip._uninstall._main(["--version"]) + result = stderr.getvalue().strip() + self.assertEqual(result, EXPECTED_VERSION_OUTPUT) + self.assertFalse(self.run_pip.called) + + @requires_usable_pip + def test_basic_uninstall(self): + with fake_pip(): + ensurepip._uninstall._main([]) + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "pip", "setuptools"] + ) + + +if __name__ == "__main__": + test.test_support.run_unittest(__name__) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 14 03:57:14 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 14 Jan 2015 02:57:14 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_webbrowser_module?= Message-ID: <20150114025706.8763.29741@psf.io> https://hg.python.org/jython/rev/a4631c4cb565 changeset: 7529:a4631c4cb565 user: Jim Baker date: Tue Jan 13 19:56:56 2015 -0700 summary: Add webbrowser module Fixes http://bugs.jython.org/issue1762054 files: Lib/webbrowser.py | 78 +++++++++++++++++++++++++++++++++++ 1 files changed, 78 insertions(+), 0 deletions(-) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py new file mode 100644 --- /dev/null +++ b/Lib/webbrowser.py @@ -0,0 +1,78 @@ +#! /usr/bin/env python +"""Interfaces for launching and remotely controlling Web browsers.""" +# Rewritten for Jython from the orginal for CPython maintained by Georg Brandl. + +import getopt +import sys +from java.awt import Desktop +from java.net import URI + +__all__ = ["Error", "open", "open_new", "open_new_tab", "get", "register"] + +class Error(Exception): + pass + +class AWTBrowser(object): + def open(self, url, new=0, autoraise=1): + if not Desktop.isDesktopSupported(): + raise Error("webbrowswer.py not supported in your environment") + try: + Desktop.getDesktop().browse(URI(url)) + return True + except IOError as e: + raise Error(e) + + def open_new(self, url): + return self.open(url, 1) + + def open_new_tab(self, url): + return self.open(url, 2) + + +# singleton, since we only support one such browser anyway in Java AWT, +# despite get/register functions +AWTBrowser = AWTBrowser() + + +def get(using=None): + """Return a browser launcher instance appropriate for the environment.""" + return AWTBrowser + + +def register(name, klass, instance=None, update_tryorder=1): + """Register a browser connector and, optionally, connection.""" + pass # ignored on Jython + +open = AWTBrowser.open +open_new = AWTBrowser.open_new +open_new_tab = AWTBrowser.open_new_tab + + +def main(): + import getopt + usage = """Usage: %s [-n | -t] url + -n: open new window + -t: open new tab""" % sys.argv[0] + try: + opts, args = getopt.getopt(sys.argv[1:], 'ntd') + except getopt.error, msg: + print >>sys.stderr, msg + print >>sys.stderr, usage + sys.exit(1) + new_win = 0 + for o, a in opts: + if o == '-n': new_win = 1 + elif o == '-t': new_win = 2 + if len(args) <> 1: + print >>sys.stderr, usage + sys.exit(1) + + url = args[0] + + open(url, new_win) + print ('opened') + + print "\a" + +if __name__ == "__main__": + main() -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Jan 15 03:07:54 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 15 Jan 2015 02:07:54 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_Pekka_Kl=C3=A4rck_as_a_?= =?utf-8?q?contributor?= Message-ID: <20150115020742.8739.29022@psf.io> https://hg.python.org/jython/rev/bd810be60074 changeset: 7530:bd810be60074 user: Jim Baker date: Wed Jan 14 18:16:30 2015 -0700 summary: Add Pekka Kl?rck as a contributor files: ACKNOWLEDGMENTS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -115,6 +115,7 @@ Darjus Loktevic Raphael Jolly Yuji Yamano + Pekka Kl?rck Local Variables: mode: indented-text -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Jan 15 03:08:38 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 15 Jan 2015 02:08:38 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Args_in_sys=2Eargv_are_now_?= =?utf-8?q?unicode_if_characters_=3E_127?= Message-ID: <20150115020833.125890.62236@psf.io> https://hg.python.org/jython/rev/d3473cb18d9e changeset: 7531:d3473cb18d9e user: Jim Baker date: Wed Jan 14 19:08:24 2015 -0700 summary: Args in sys.argv are now unicode if characters > 127 As was seen in similar fixes for os.environ and os.listdir, Java presents command line arguments as java.lang.String, with additional encoding. For each argument in sys.argv, convert to str if ascii (maintaining current behavior), otherwise unicode. Fixes http://bugs.jython.org/issue2252 files: Lib/test/test_sys_jy.py | 27 ++++++++++--- src/org/python/core/PySystemState.java | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_sys_jy.py b/Lib/test/test_sys_jy.py --- a/Lib/test/test_sys_jy.py +++ b/Lib/test/test_sys_jy.py @@ -2,6 +2,7 @@ from __future__ import with_statement import os import re +import subprocess import sys import tempfile import unittest @@ -240,15 +241,29 @@ self.assertEqual(check(0xa2, None, "backslashreplace"), r"\xa2") self.assertEqual(check(0xa2, "cp850"), "\xbd") +class SysArgvTest(unittest.TestCase): + def test_unicode_argv(self): + """Unicode roundtrips successfully through sys.argv arguments""" + zhongwen = u'\u4e2d\u6587' + with test_support.temp_cwd(name=u"tempcwd-%s" % zhongwen): + p = subprocess.Popen( + [sys.executable, '-c', + 'import sys;' \ + 'sys.stdout.write(sys.argv[1].encode("utf-8"))', + zhongwen], + stdout=subprocess.PIPE) + self.assertEqual(p.stdout.read().decode("utf-8"), zhongwen) + def test_main(): test_support.run_unittest( - SysTest, - ShadowingTest, - SyspathResourceTest, - SyspathUnicodeTest, - SysEncodingTest, - ) + SysTest, + ShadowingTest, + SyspathResourceTest, + SyspathUnicodeTest, + SysEncodingTest, + SysArgvTest + ) if __name__ == "__main__": test_main() diff --git a/src/org/python/core/PySystemState.java b/src/org/python/core/PySystemState.java --- a/src/org/python/core/PySystemState.java +++ b/src/org/python/core/PySystemState.java @@ -1130,7 +1130,7 @@ PyList argv = new PyList(); if (args != null) { for (String arg : args) { - argv.append(new PyString(arg)); + argv.append(Py.newStringOrUnicode(arg)); } } return argv; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Jan 17 05:50:36 2015 From: jython-checkins at python.org (jim.baker) Date: Sat, 17 Jan 2015 04:50:36 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Upgrade_to_JLine2_and_add_t?= =?utf-8?q?ab_completion_support?= Message-ID: <20150117044917.104128.15249@psf.io> https://hg.python.org/jython/rev/ca92ffdff93f changeset: 7532:ca92ffdff93f user: Jim Baker date: Fri Jan 16 21:49:07 2015 -0700 summary: Upgrade to JLine2 and add tab completion support Fixes getpass.getpass so that user input is not echoed. Should provide better support for help on Windows in a future fix (http://bugs.jython.org/issue2209) Adds tab completion support, much like Python 3.4 (http://bugs.python.org/issue5845). A further fix is needed to see if we can get tab insertion after whitespace. Note that JLine2 really wants the tab key to map to a completer. Fixes http://bugs.jython.org/issue2092 files: Lib/getpass.py | 23 +- Lib/readline.py | 49 +--- Lib/site.py | 9 + build.xml | 6 +- extlibs/jline-1.0.jar | Bin extlibs/jline-2.12.jar | Bin src/org/python/core/Py.java | 18 +- src/org/python/util/InteractiveConsole.java | 8 + src/org/python/util/InteractiveInterpreter.java | 2 +- src/org/python/util/JLineConsole.java | 105 +++------ src/org/python/util/jline-keybindings.properties | 64 ------ 11 files changed, 97 insertions(+), 187 deletions(-) diff --git a/Lib/getpass.py b/Lib/getpass.py --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -25,23 +25,14 @@ Restore terminal settings at end. """ - if stream is None: - stream = sys.stdout try: - terminal = sys._jy_console.reader.terminal + reader = sys._jy_console.reader except: return default_getpass(prompt) - - echoed = terminal.getEcho() - terminal.disableEcho() - try: - passwd = _raw_input(prompt, stream) - finally: - if echoed: - terminal.enableEcho() - - stream.write('\n') - return passwd + if stream is not None: + stream.write(prompt) + prompt = '' + return reader.readLine(prompt, '\0').encode(sys._jy_console.encoding) def unix_getpass(prompt='Password: ', stream=None): @@ -148,9 +139,7 @@ from EasyDialogs import AskPassword except ImportError: if os.name == 'java': - # disable this option for now, this does not reliably work - # getpass = jython_getpass - getpass = default_getpass + getpass = jython_getpass else: getpass = AskPassword else: diff --git a/Lib/readline.py b/Lib/readline.py --- a/Lib/readline.py +++ b/Lib/readline.py @@ -1,9 +1,14 @@ -from __future__ import with_statement import os.path import sys from warnings import warn -import java.lang.reflect.Array +try: + # jarjar-ed version + from org.python.jline.console.history import MemoryHistory +except ImportError: + # dev version from extlibs + from jline.console.history import MemoryHistory + __all__ = ['add_history', 'clear_history', 'get_begidx', 'get_completer', 'get_completer_delims', 'get_current_history_length', @@ -18,7 +23,7 @@ _console = sys._jy_console _reader = _console.reader except AttributeError: - raise ImportError("Cannot access JLineConsole reader") + raise ImportError("Cannot access JLine2 setup") _history_list = None @@ -51,21 +56,7 @@ _setup_history() def parse_and_bind(string): - if string == "tab: complete": - try: - keybindings_field = _reader.class.getDeclaredField("keybindings") - keybindings_field.setAccessible(True) - keybindings = keybindings_field.get(_reader) - COMPLETE = _reader.KEYMAP_NAMES.get('COMPLETE') - if java.lang.reflect.Array.getShort(keybindings, 9) != COMPLETE: - java.lang.reflect.Array.setShort(keybindings, 9, COMPLETE) - except: - warn("Cannot bind tab key to complete. You need to do this in a .jlinebindings.properties file instead", SecurityWarning, stacklevel=2) - else: - warn("Cannot bind key %s. You need to do this in a .jlinebindings.properties file instead" % (string,), NotImplementedWarning, stacklevel=2) - -def get_line_buffer(): - return str(_reader.cursorBuffer.buffer) + pass def insert_text(string): _reader.putString(string) @@ -87,7 +78,7 @@ def write_history_file(filename="~/.history"): expanded = os.path.expanduser(filename) with open(expanded, 'w') as f: - for line in _reader.history.historyList: + for line in _reader.history.entries(): f.write(line) f.write("\n") @@ -95,7 +86,7 @@ _reader.history.clear() def add_history(line): - _reader.history.addToHistory(line) + _reader.history.add(line) def get_history_length(): return _reader.history.maxSize @@ -104,32 +95,26 @@ _reader.history.maxSize = length def get_current_history_length(): - return len(_reader.history.historyList) + return _reader.history.size() def get_history_item(index): # JLine indexes from 0 while readline indexes from 1 (at least in test_readline) if index>0: - return _reader.history.historyList[index-1] + return _reader.history.get(index-1) else: return None def remove_history_item(pos): - if _history_list: - _history_list.remove(pos) - else: - warn("Cannot remove history item at position: %s" % (pos,), SecurityWarning, stacklevel=2) + _reader.history.remove(pos) def replace_history_item(pos, line): - if _history_list: - _history_list.set(pos, line) - else: - warn("Cannot replace history item at position: %s" % (pos,), SecurityWarning, stacklevel=2) + _reader.history.set(pos, line) def redisplay(): _reader.redrawLine() def set_startup_hook(function=None): - _console.startupHook = function + _console.startup_hook = function def set_pre_input_hook(function=None): warn("set_pre_input_hook %s" % (function,), NotImplementedWarning, stacklevel=2) @@ -161,7 +146,7 @@ break return start - _reader.addCompletor(complete_handler) + _reader.addCompleter(complete_handler) def get_completer(): diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -66,6 +66,15 @@ _is_jython = sys.platform.startswith("java") if _is_jython: _ModuleType = type(os) + # Follow what Python 3.4 has done, http://bugs.python.org/issue5845 + # FIXME add tab-as-indent support if preceding is whitespace + try: + import readline + except ImportError: + pass + else: + import rlcompleter + readline.parse_and_bind("tab: complete") # Prefixes for site-packages; add additional prefixes like /usr/local here PREFIXES = [sys.prefix, sys.exec_prefix] diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -178,7 +178,7 @@ - + @@ -629,10 +629,8 @@ - - diff --git a/extlibs/jline-1.0.jar b/extlibs/jline-1.0.jar deleted file mode 100644 index d25927961d4246484403f772a6cebf9badaf857c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jline-2.12.jar b/extlibs/jline-2.12.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..41676a1e210dec6f80cb730830b69dab202a0852 GIT binary patch [stripped] diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -24,11 +24,13 @@ import java.util.Set; import com.google.common.base.CharMatcher; +import jline.console.UserInterruptException; import jnr.constants.Constant; import jnr.constants.platform.Errno; import jnr.posix.POSIX; import jnr.posix.POSIXFactory; +import jnr.posix.util.Platform; import org.python.antlr.base.mod; import org.python.core.adapter.ClassicPyObjectAdapter; import org.python.core.adapter.ExtensiblePyObjectAdapter; @@ -144,6 +146,14 @@ public static PyException OSError(Constant errno, PyObject filename) { int value = errno.intValue(); + // see https://github.com/jruby/jruby/commit/947c661e46683ea82f8016dde9d3fa597cd10e56 + // for rationale to do this mapping, but in a nutshell jnr-constants is automatically + // generated from header files, so that's not the right place to do this mapping, + // but for Posix compatibility reasons both CPython andCRuby do this mapping; + // except CPython chooses EEXIST instead of CRuby's ENOENT + if (Platform.IS_WINDOWS && (value == 20047 || value == Errno.ESRCH.intValue())) { + value = Errno.EEXIST.intValue(); + } // Pass to strerror because jnr-constants currently lacks Errno descriptions on // Windows, and strerror falls back to Linux's PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value), filename); @@ -172,9 +182,9 @@ return new PyException(Py.RuntimeError, message); } public static PyObject KeyboardInterrupt; - /*public static PyException KeyboardInterrupt(String message) { - return new PyException(Py.KeyboardInterrupt, message); - }*/ + public static PyException KeyboardInterrupt(String message) { + return new PyException(Py.KeyboardInterrupt, message); + } public static PyObject FloatingPointError; public static PyException FloatingPointError(String message) { @@ -527,6 +537,8 @@ return Py.RuntimeError("maximum recursion depth exceeded (Java StackOverflowError)"); } else if (t instanceof OutOfMemoryError) { memory_error((OutOfMemoryError) t); + } else if (t instanceof UserInterruptException) { + return Py.KeyboardInterrupt(""); } PyObject exc = PyJavaType.wrapJavaObject(t); PyException pyex = new PyException(exc.getType(), exc); diff --git a/src/org/python/util/InteractiveConsole.java b/src/org/python/util/InteractiveConsole.java --- a/src/org/python/util/InteractiveConsole.java +++ b/src/org/python/util/InteractiveConsole.java @@ -134,6 +134,14 @@ } write("\n"); break; + } catch (Throwable t) { + // catch jline.console.UserInterruptException, rethrow as a KeyboardInterrupt + throw Py.JavaError(t); + // One would expect that it would be possible to then catch the KeyboardInterrupt at the + // bottom of this loop, however, for some reason the control-C restores the input text, + // so simply doing + // resetbuffer(); more = false; + // is not sufficient } more = push(line); } diff --git a/src/org/python/util/InteractiveInterpreter.java b/src/org/python/util/InteractiveInterpreter.java --- a/src/org/python/util/InteractiveInterpreter.java +++ b/src/org/python/util/InteractiveInterpreter.java @@ -147,7 +147,7 @@ Py.stderr.write(data); } - public StringBuffer buffer = new StringBuffer(); + public StringBuilder buffer = new StringBuilder(); public String filename = ""; public void resetbuffer() { diff --git a/src/org/python/util/JLineConsole.java b/src/org/python/util/JLineConsole.java --- a/src/org/python/util/JLineConsole.java +++ b/src/org/python/util/JLineConsole.java @@ -5,20 +5,19 @@ import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStreamWriter; import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Arrays; import java.util.List; -import jline.ConsoleReader; -import jline.Terminal; +import jline.console.ConsoleKeys; +import jline.console.ConsoleReader; import jline.WindowsTerminal; +import jline.console.history.FileHistory; import jnr.constants.platform.Errno; import org.python.core.PlainConsole; @@ -76,6 +75,22 @@ // ... not "jline.UnixTerminal.input.encoding" as you might think, not even in JLine2 } + private static class HistoryCloser implements Runnable { + FileHistory history; + public HistoryCloser(FileHistory history) { + this.history = history; + } + + @Override + public void run() { + try { + history.flush(); + } catch (IOException e) { + // could not save console history, but quietly ignore in this case + } + } + } + /** * {@inheritDoc} *

@@ -85,34 +100,25 @@ */ @Override public void install() { - Terminal.setupTerminal(); - String userHomeSpec = System.getProperty("user.home", "."); // Configure a ConsoleReader (the object that does most of the line editing). try { - /* - * Wrap System.out in the specified encoding. jline.ConsoleReader.readLine() echoes the - * line through this Writer. - */ - Writer out = new PrintWriter(new OutputStreamWriter(System.out, encoding)); - - // Get the key bindings (built in ones treat TAB Pythonically). - InputStream bindings = getBindings(userHomeSpec, getClass().getClassLoader()); - // Create the reader as unbuffered as possible InputStream in = new FileInputStream(FileDescriptor.in); - reader = new ConsoleReader(in, out, bindings); + reader = new ConsoleReader("jython", in, System.out, null, encoding); + reader.setKeyMap("jython"); + reader.setHandleUserInterrupt(true); // We find the bell too noisy reader.setBellEnabled(false); /* - * Everybody else, using sys.stdout or java.lang.System.out gets to write on a special + * Everybody else, using sys.stdout or java.lang.System.out, gets to write on a special * PrintStream that keeps the last incomplete line in case it turns out to be a console * prompt. */ - outWrapper = new ConsoleOutputStream(System.out, reader.getTermwidth()); + outWrapper = new ConsoleOutputStream(System.out, reader.getTerminal().getWidth()); System.setOut(new PrintStream(outWrapper, true, encoding)); } catch (IOException e) { @@ -122,7 +128,9 @@ // Access and load (if possible) the line history. try { File historyFile = new File(userHomeSpec, ".jline-jython.history"); - reader.getHistory().setHistoryFile(historyFile); + FileHistory history = new FileHistory(historyFile); + Runtime.getRuntime().addShutdownHook(new Thread(new HistoryCloser(history))); + reader.setHistory(history); } catch (IOException e) { // oh well, no history from file } @@ -185,14 +193,19 @@ startup_hook.__call__(); } + try { + // Resumption from control-Z suspension may occur without JLine telling us + // Work around by putting the terminal into a well-known state before + // each read line, if possible + reader.getTerminal().init(); + } catch (Exception exc) {} + // Send the cursor to the start of the line (no prompt, empty buffer). - reader.setDefaultPrompt(null); + reader.setPrompt(null); reader.redrawLine(); // The prompt is whatever was already on the line. - String line = reader.readLine(prompt); - return line; - + return reader.readLine(prompt); } catch (IOException ioe) { // Something went wrong, or we were interrupted (seems only BSD throws this) if (!fromSuspend(ioe)) { @@ -203,7 +216,7 @@ // The interruption seems to be (return from) a ctrl-Z suspension: try { // Must reset JLine and continue (not repeating the prompt) - reader.getTerminal().initializeTerminal(); + reader.resetPromptLine (prompt, null, 0); prompt = ""; } catch (Exception e) { // Do our best to say what went wrong @@ -216,46 +229,6 @@ } /** - * Return the JLine bindings file. - * - * This handles loading the user's custom key bindings (normally JLine does) so it can fall back - * to Jython's (which disable tab completion) when the user's are not available. - * - * @return an InputStream of the JLine bindings file. - */ - protected static InputStream getBindings(String userHomeSpec, ClassLoader loader) { - - // The key bindings file may be specified explicitly - String bindingsFileSpec = System.getProperty("jline.keybindings"); - File bindingsFile; - - if (bindingsFileSpec != null) { - // Bindings file explicitly specified - bindingsFile = new File(bindingsFileSpec); - } else { - // Otherwise try ~/.jlinebindings.properties - bindingsFile = new File(userHomeSpec, ".jlinebindings.properties"); - } - - // See if that file really exists (and can be read) - try { - if (bindingsFile.isFile()) { - try { - return new FileInputStream(bindingsFile); - } catch (FileNotFoundException fnfe) { - // Shouldn't really ever happen - fnfe.printStackTrace(); - } - } - } catch (SecurityException se) { - // continue - } - - // User/specific key bindings could not be read: use the ones from the class path or jar. - return loader.getResourceAsStream("org/python/util/jline-keybindings.properties"); - } - - /** * Determine if the IOException was likely caused by a SIGSTP (ctrl-z). Seems only applicable to * BSD platforms. */ diff --git a/src/org/python/util/jline-keybindings.properties b/src/org/python/util/jline-keybindings.properties deleted file mode 100644 --- a/src/org/python/util/jline-keybindings.properties +++ /dev/null @@ -1,64 +0,0 @@ -# Keybinding mapping for JLine. The format is: -# [key code]: [logical operation] - -# CTRL-B: move to the previous character -2: PREV_CHAR - -# CTRL-G: move to the previous word -7: PREV_WORD - -# CTRL-F: move to the next character -6: NEXT_CHAR - -# CTRL-A: move to the beginning of the line -1: MOVE_TO_BEG - -# CTRL-D: close out the input stream -4: EXIT - -# CTRL-E: move the cursor to the end of the line -5: MOVE_TO_END - -# BACKSPACE, CTRL-H: delete the previous character -# 8 is the ASCII code for backspace and therefor -# deleting the previous character -8: DELETE_PREV_CHAR - -## TAB, CTRL-I: signal that console completion should be attempted -#9: COMPLETE -# Jython needs a real TAB, disable completion -9: UNKNOWN - -# CTRL-J, CTRL-M: newline -10: NEWLINE - -# CTRL-K: erase the current line -11: KILL_LINE - -# ENTER: newline -13: NEWLINE - -# CTRL-L: clear screen -12: CLEAR_SCREEN - -# CTRL-N: scroll to the next element in the history buffer -14: NEXT_HISTORY - -# CTRL-P: scroll to the previous element in the history buffer -16: PREV_HISTORY - -# CTRL-R: redraw the current line -18: REDISPLAY - -# CTRL-U: delete all the characters before the cursor position -21: KILL_LINE_PREV - -# CTRL-V: paste the contents of the clipboard (useful for Windows terminal) -22: PASTE - -# CTRL-W: delete the word directly before the cursor -23: DELETE_PREV_WORD - -# DELETE, CTRL-?: delete the previous character -# 127 is the ASCII code for delete -127: DELETE_PREV_CHAR -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Jan 17 19:00:19 2015 From: jython-checkins at python.org (jim.baker) Date: Sat, 17 Jan 2015 18:00:19 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Encoding_for_ACKNOWLEDGMENT?= =?utf-8?q?S?= Message-ID: <20150117180015.93187.63961@psf.io> https://hg.python.org/jython/rev/d60d090d4f40 changeset: 7533:d60d090d4f40 user: Jim Baker date: Sat Jan 17 10:59:53 2015 -0700 summary: Encoding for ACKNOWLEDGMENTS files: ACKNOWLEDGMENTS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- ACKNOWLEDGMENTS Copyright (c) Corporation for National Research Initiatives -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Jan 17 19:00:19 2015 From: jython-checkins at python.org (jim.baker) Date: Sat, 17 Jan 2015 18:00:19 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Expand_tab_to_4_spaces_if_a?= =?utf-8?q?_continuation_line_in_the_console?= Message-ID: <20150117180015.118100.912@psf.io> https://hg.python.org/jython/rev/f367b4f22d61 changeset: 7534:f367b4f22d61 user: Jim Baker date: Sat Jan 17 11:00:09 2015 -0700 summary: Expand tab to 4 spaces if a continuation line in the console Follows the approach suggested in http://bugs.python.org/issue5845 Ideally we would not expand the tab, but insert a tab literal. However this confuses JLine2 with respect to the cursor position upon subsequent edits of this line. One can still copy&paste code with tab literals, although only limited editing is available on the last line in this scenario. files: Lib/readline.py | 22 ++++++++++++++- src/org/python/util/JLineConsole.java | 4 +-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Lib/readline.py b/Lib/readline.py --- a/Lib/readline.py +++ b/Lib/readline.py @@ -134,7 +134,27 @@ def complete_handler(buffer, cursor, candidates): start = _get_delimited(buffer, cursor)[0] delimited = buffer[start:cursor] - for state in xrange(100): # TODO arbitrary, what's the number used by gnu readline? + + if _reader.prompt == sys.ps2 and (not delimited or delimited.isspace()): + # Insert tab (as expanded to 4 spaces), but only if if + # preceding is whitespace/empty and in console + # continuation; this is a planned featue for Python 3 per + # http://bugs.python.org/issue5845 + # + # Ideally this would not expand tabs, in case of mixed + # copy&paste of tab-indented code, however JLine2 gets + # confused as to the cursor position if certain, but not + # all, subsequent editing if the tab is backspaced + candidates.add(" " * 4) + return start + + # TODO: if there are a reasonably large number of completions + # (need to get specific numbers), CPython 3.4 will show a + # message like so: + # >>> + # Display all 186 possibilities? (y or n) + # Currently Jython arbitrarily limits this to 100 and displays them + for state in xrange(100): completion = None try: completion = function(delimited, state) diff --git a/src/org/python/util/JLineConsole.java b/src/org/python/util/JLineConsole.java --- a/src/org/python/util/JLineConsole.java +++ b/src/org/python/util/JLineConsole.java @@ -9,12 +9,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; -import java.net.MalformedURLException; -import java.net.URL; import java.util.Arrays; import java.util.List; -import jline.console.ConsoleKeys; import jline.console.ConsoleReader; import jline.WindowsTerminal; import jline.console.history.FileHistory; @@ -109,6 +106,7 @@ reader = new ConsoleReader("jython", in, System.out, null, encoding); reader.setKeyMap("jython"); reader.setHandleUserInterrupt(true); + reader.setCopyPasteDetection(true); // We find the bell too noisy reader.setBellEnabled(false); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Jan 18 06:36:22 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 18 Jan 2015 05:36:22 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_ACKNOWLEDGMENTS_so_i?= =?utf-8?q?t_is_not_so_dated_and_describes_third_party_libraries?= Message-ID: <20150118053520.93185.89432@psf.io> https://hg.python.org/jython/rev/b42fbbbfcdaa changeset: 7535:b42fbbbfcdaa user: Jim Baker date: Sat Jan 17 22:35:08 2015 -0700 summary: Update ACKNOWLEDGMENTS so it is not so dated and describes third party libraries files: ACKNOWLEDGMENTS | 83 ++++++++++++++++++++++++------------ 1 files changed, 55 insertions(+), 28 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -1,47 +1,74 @@ # -*- coding: utf-8 -*- ACKNOWLEDGMENTS -Copyright (c) Corporation for National Research Initiatives - Jim Hugunin invented JPython and was the primary developer while - he was at CNRI. In February 1999, Jim left CNRI for sunny - California and Barry Warsaw became the primary maintainer. - When Barry and the rest of PythonLabs left CNRI, Barry renamed - JPython to Jython, put the sources on SourceForge and made - Finn Bock the primary maintainer. +Jython: Python for the Java Platform - Python's inventor Guido van Rossum and the rest of PythonLabs - continues to help and support Jython by their understanding - of how Jython must live with the limits of Java. +Copyright (c) 2000-2014 Jython Developers. +All rights reserved. - You can contact the Jython maintainers directly via - jython-dev at lists.sourceforge.net, or the Jython community at - jython-users at lists.sourceforge.net. +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. - Harry Mantakos contributed the underlying md5 implementation. +Copyright (c) 2000 The Apache Software Foundation. +All rights reserved. - The SHA1 implementation is taken from cryptix. +Copyright (c) 1995-2000 Corporation for National Research Initiatives. +All Rights Reserved. - Samuele Pedroni has designed and implemented the improved - PackageManagers and java reload support and also fixed a lot - of bugs. +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved. - Kevin Butler has written and contributed the code for os.environ and - os.system(). +Jython links the following libraries: - Brian Zimmer contributed zxJDBC which is a Python DB API subsystem. +* Antlr 3, licensed under the Antlr 3 (BSD) license +* ASM 5, licensed under a BSD license from France T?l?com +* BouncyCastle, licensed under a MIT license from The Legion of the + Bouncy Castle Inc. +* Apache Commons Compression and Xerces, licensed under an Apache 2.0 + License from the Apache Software Foundation +* Google Guava, licensed under an Apache 2.0 License from Google +* Jar Jar Links, licensed uner the Apache 2.0 License from Tonic Systems +* Java Native Runtime, licensed under the Common Public License +* JLine2, licensed under a BSD license +* JUnit, licenseed under Eclipse Public License 1.0 from the JUnit project +* Mock Runner, licensed under the Apache 1.1 license +* Netty 4, licensed under the Apache 2.0 license from the Netty project - Cyrille Morvan has written the code for the Jythonc ant task. +Jython follows closely the Python language and its reference +implementation CPython, as created by Guido van Rossum. +Jython 2.7 corresponds to CPython 2.7. - Alan Kennedy contributed modjy, which bridges WSGI to the Servlet API +Jython started as JPython, created by Jim Hugunin in 1997. JPython was +renamed to Jython by Barry Warsaw in 1999 with the 2.0 release. Since +then, Jython 2.x releases have corresponded to equivalent CPython 2.x +releases. - Chris Gokey, David Syer and Finn Bock added PyServlet. +Contacts: + +* Jython developers jython-dev at lists.sourceforge.net +* Jython user community jython-users at lists.sourceforge.net. + +Samuele Pedroni contributed package manager support. + +Brian Zimmer contributed zxJDBC to provide Python DB API using JDBC. + +Cyrille Morvan contributed the code for the Jythonc ant task. + +Alan Kennedy contributed modjy, which bridges WSGI to the Servlet API + +Chris Gokey, David Syer and Finn Bock added PyServlet. - Yin Wang and Steve Yegge contributed the static analyzer from Google (also called indexer). +Yin Wang and Steve Yegge contributed the static analyzer from Google +(also called indexer). - A huge thanks goes to all the members of the jpython/jython - mailing lists. Other folks who have contributed to JPython and - Jython in ways large and small, in no particular order: +The Jython startup script (bin/jython) was adapted from the similar +script written for JRuby. +A huge thanks goes to all the members of the jpython/jython +mailing lists. Other folks who have contributed to JPython and +Jython in ways large and small, in no particular order: + + Kevin Butler Greg Ward Tony Plate Jim Althoff -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Jan 18 06:39:17 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 18 Jan 2015 05:39:17 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_Harry_Mantakos_as_a_con?= =?utf-8?q?tributor?= Message-ID: <20150118053829.93175.2822@psf.io> https://hg.python.org/jython/rev/31de55e43da2 changeset: 7536:31de55e43da2 user: Jim Baker date: Sat Jan 17 22:38:25 2015 -0700 summary: Add Harry Mantakos as a contributor files: ACKNOWLEDGMENTS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -69,6 +69,7 @@ Jython in ways large and small, in no particular order: Kevin Butler + Harry Mantakos Greg Ward Tony Plate Jim Althoff -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Jan 18 07:28:09 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 18 Jan 2015 06:28:09 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_NEWS_for_2=2E7b4?= Message-ID: <20150118062808.69918.74090@psf.io> https://hg.python.org/jython/rev/211062f255d8 changeset: 7537:211062f255d8 user: Jim Baker date: Sat Jan 17 23:28:04 2015 -0700 summary: Update NEWS for 2.7b4 files: NEWS | 69 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 68 insertions(+), 1 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -1,9 +1,75 @@ Jython NEWS +For more details, please see https://hg.python.org/jython + Jython 2.7b4 Bugs Fixed + - [ 2032 ] Fixed typo in compiler/pycodegen.py + - [ 2190 ] Raise ValueError when unichr() is called with isolated surrogate codepoint + - [ 1057 ] Finalizer support (__del__) for new style classes + - [ 2192 ] Server requests were hanging using jython, django and django-jython + - [ 2204 ] Minimum (core) install will now suport Jython console + - [ 2184 ] inspect.callargs, including anonymous tuples in function params + - [ 2100 ] Fix deficiencies in PyUnicode beyond the BMP + - Fix bug in supporting meta path importers for six + - [ 2183 ] Rework function attributes support + - [ 2115 ] Allow bound methods as arg for single method interface param + - [ 2163 ] Refactor Py, PySystemState to init constants early + - [ 2217 ] Update serial release to 3 for sys.version_info + - [ 2090, 1494 ] Behaviour of long in the JSR-223 engine + - [ 2196 ] Do not emit duplicate entries in building standalone jar + - [ 1708 ] Ensure regrtest runs in a C locale to avoid failures + - [ 2037 ] Prevent non-byte values appearing in str() + - [ 2205 ] Guard via module import lock all entry points from Java into import + - [ 1631 ] Fully proxy java.util.Map objects as Python dicts + - [ 2215 ] Fully proxy java.util.List objects as Python lists + - [ 2242 ] select.select and related socket.connect_ex fixes + - [ 2241 ] Fully proxy java.util.Set objects as Python sets + - [ 2239, 1825 ] os.getenv, os.listdir may return unicode instead of bytes + - [ 2110 ] Update Java Native Runtime jars - [ 2236 ] Interactive parser does not accept try ... except E as e: syntax - - [ 2037 ] Byte-string containing elements greater than 255 + - [ 2232 ] Visit class decorators when visiting class def in scopes compilation + - [ 2247 ] dict.pop should not add additional quoting in KeyError + - [ 2238 ] os.system now uses a simpler wrapping of ProcessBuilder + - [ 1561 ] Raises NotImplementedError if abstract method from Java is not implemented + - [ 2221 ] Implement Popen.pid + - [ 2150 ] Fix regrtest to support -x to exclude tests + - [ 1152612 ] All dict methods for __dict__ except views + - [ 1762054 ] Add webbrowser module + - [ 2252 ] Args in sys.argv are now unicode if characters > 127 + - [ 2092 ] Upgrade to JLine2 and add tab completion support + - [ 2236 ] Interactive parser does not accept try ... except E as e: syntax + - [ 2237 ] More robust math/cmath support (ongoing) + + New features + - Full support of Python buffer protocol, along with Java ByteBuffer support + - Add index to PyUnicode facilitating O(1) access to strings beyond the BMP. + - java.util.{Map, List, Set} are now treated as subclasses of the + corresponding Python abstract base classes + - jythonlib module to simplify usage of Java internals from Python; + weakref collections now directly use corresponding collections from + Google Guava and java.util + - CPython's _json.c was ported to Java to speed up JSON encoding/decoding + - Upgraded third party libraries + - Initial support for ensurepip module + + Potentially backwards breaking changes, removing silent errors: + + - remove method on proxied List objects now follows Python + sematics: a ValueError is raised if the item is not found in the + java.util.List. In the past, Java semantics were used, with a + boolean returned indicating if the item was removed or + not. Given how this interacted with Jython, such remove + invocations were in the past silent, and perhaps were actually a + bug. + + - d[key_not_present], if d implement java.util.Map, no longer + returns None, but raises KeyError, which means this behavior now + matches standard dict semantics. + + - Abstract methods of an inherited class or interface from Java now raise + NotImplementedError, instead of returning None (in Java, null) or some + "zero", if they are not implemented in the extending Python class. Jython 2.7b3 Bugs Fixed @@ -15,6 +81,7 @@ New Features - [ 1896215 ] findResource(s) for SyspathJavaLoader - [ 1591 ] Interactive interpreter stuck on '...' loop + - Added socket reboot work, using Netty 4 to fully support socket, select, and ssl API Jython 2.7b2 Bugs Fixed -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 19 17:15:33 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 19 Jan 2015 16:15:33 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fixes_paging_for_the_help_f?= =?utf-8?q?unction_on_Windows?= Message-ID: <20150119161505.93201.60444@psf.io> https://hg.python.org/jython/rev/6e8e76987965 changeset: 7538:6e8e76987965 user: Jim Baker date: Mon Jan 19 09:15:00 2015 -0700 summary: Fixes paging for the help function on Windows On Windows, the text pager for the help function was not being properly selected, due to os.name/os._name differences. However, even if this OS testing is fixed, the use of subprocess to use the more command to page was hanging. Now uses a JLine2 specific pager if JLine2 is available that emulates a subset of less functionality, namely paging backwards, otherwise a plainpager (simply write lines to stdout). Fixes http://bugs.jython.org/issue2209 files: Lib/pydoc.py | 110 ++++++++++++++++++++++++++++++++++++-- 1 files changed, 102 insertions(+), 8 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -64,6 +64,8 @@ def popleft(self): return self.pop(0) +_is_windows = sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt') + # --------------------------------------------------------- common routines def pathdirs(): @@ -598,7 +600,7 @@ try: path = inspect.getabsfile(object) url = path - if sys.platform == 'win32': + if _is_windows: import nturl2path url = nturl2path.pathname2url(path) filelink = '%s' % (url, path) @@ -1328,6 +1330,14 @@ line += '\n' + self.indent(str(doc)) return line +class AnsiDoc(TextDoc): + """Formatter class for ANSI texst documentation.""" + + def bold(self, text): + """Format a string in bold by overstriking.""" + return "\x1b[1m" + text + "\x1b[0m" + + # --------------------------------------------------------- user interfaces def pager(text): @@ -1336,14 +1346,95 @@ pager = getpager() pager(text) + +class JLine2Pager(object): + + + @staticmethod + def available(): + try: + sys._jy_console.reader + return True + except AttributeError: + return False + + def __init__(self, lines): + self.data = lines.split("\n") + self.reader = sys._jy_console.reader + self.index = 0 + ansi_codes = { + "bold": "\x1b[1m", + "negative": "\x1b[7m", + "normal": "\x1b[0m" + } + self.more_prompt_back = "--more-- space/{bold}b{normal}ack/{bold}q{normal}uit:".format(**ansi_codes) + self.more_prompt = "--more-- space/{bold}q{normal}uit:".format(**ansi_codes) + self.end_prompt_back = "{negative}(END){normal} {bold}b{normal}ack/{bold}q{normal}uit:".format(**ansi_codes) + self.end_prompt = "{negative}(END){normal} {bold}q{normal}uit:".format(**ansi_codes) + + @property + def visible(self): + # The terminal may be resized at any time by the user, + # so check terminal.height on each iteration + return self.reader.terminal.height - 1 + + def handle_prompt(self): + can_go_back = self.index - self.visible > 0 + if self.index == len(self.data): + if can_go_back: + self.reader.resetPromptLine(self.end_prompt_back, "", 0) + else: + self.reader.resetPromptLine(self.end_prompt, "", 0) + else: + if can_go_back: + self.reader.resetPromptLine(self.more_prompt_back, "", 0) + else: + self.reader.resetPromptLine(self.more_prompt, "", 0) + c = chr(self.reader.readCharacter()) + self.reader.resetPromptLine("", "", 0) + if c == "q": + return "quit" + elif c == "b": + if not can_go_back: + return "reprompt" + self.index -= self.visible * 2 + if self.index < 0: + self.index = 0 + elif self.index != len(self.data): + return "forward" + else: + return "reprompt" + + def page(self): + # TODO count wrapped lines with respect to terminal width by + # taking in account ANSI formatting codes + row_count = 0 + while self.index < len(self.data): + line = self.data[self.index] + self.reader.print(line + "\n") + self.index += 1 + row_count += 1 + if row_count == self.visible or self.index == len(self.data): + while True: + action = self.handle_prompt() + if action == "quit": + return + elif action != "reprompt": + break + row_count = 0 + self.reader.resetPromptLine("", "", 0) + + def getpager(): """Decide what method to use for paging through text.""" + if _is_windows and JLine2Pager.available(): + return lambda text: JLine2Pager(text).page() if type(sys.stdout) is not types.FileType: return plainpager if not sys.stdin.isatty() or not sys.stdout.isatty(): return plainpager if 'PAGER' in os.environ: - if sys.platform == 'win32': # pipes completely broken in Windows + if _is_windows: # pipes completely broken in Windows return lambda text: tempfilepager(plain(text), os.environ['PAGER']) elif os.environ.get('TERM') in ('dumb', 'emacs'): return lambda text: pipepager(plain(text), os.environ['PAGER']) @@ -1351,7 +1442,7 @@ return lambda text: pipepager(text, os.environ['PAGER']) if os.environ.get('TERM') in ('dumb', 'emacs'): return plainpager - if sys.platform == 'win32' or sys.platform.startswith('os2'): + if _is_windows or sys.platform.startswith('os2'): return lambda text: tempfilepager(plain(text), 'more <') if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: return lambda text: pipepager(text, 'less') @@ -1484,7 +1575,10 @@ # --------------------------------------- interactive interpreter interface -text = TextDoc() +if _is_windows and JLine2Pager.available(): + text = AnsiDoc() +else: + text = TextDoc() html = HTMLDoc() class _OldStyleClass: pass @@ -2110,7 +2204,7 @@ self.search_ent.bind('', self.search) self.stop_btn = Tkinter.Button(self.search_frm, text='stop', pady=0, command=self.stop, state='disabled') - if sys.platform == 'win32': + if _is_windows: # Trying to hide and show this button crashes under Windows. self.stop_btn.pack(side='right') @@ -2126,7 +2220,7 @@ self.search_frm.pack(side='top', fill='x') self.search_ent.focus_set() - font = ('helvetica', sys.platform == 'win32' and 8 or 10) + font = ('helvetica', _is_windows and 8 or 10) self.result_lst = Tkinter.Listbox(window, font=font, height=6) self.result_lst.bind('', self.select) self.result_lst.bind('', self.goto) @@ -2172,7 +2266,7 @@ import webbrowser webbrowser.open(url) except ImportError: # pre-webbrowser.py compatibility - if sys.platform == 'win32': + if _is_windows: os.system('start "%s"' % url) else: rc = os.system('netscape -remote "openURL(%s)" &' % url) @@ -2217,7 +2311,7 @@ self.search_lbl.config(text='Search for') self.search_lbl.pack(side='left') self.search_ent.pack(side='right', fill='x', expand=1) - if sys.platform != 'win32': self.stop_btn.forget() + if not _is_windows: self.stop_btn.forget() self.stop_btn.config(state='disabled') def select(self, event=None): -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 19 21:05:15 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 19 Jan 2015 20:05:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Remove_unsupported_GNU_read?= =?utf-8?q?line_console_support=2E?= Message-ID: <20150119200511.118096.1003@psf.io> https://hg.python.org/jython/rev/3bd877d4912d changeset: 7539:3bd877d4912d user: Jim Baker date: Mon Jan 19 12:59:12 2015 -0700 summary: Remove unsupported GNU readline console support. Use JLineConsole instead, which is enabled by default for interactive usage. files: build.xml | 1 - registry | 7 +- src/org/python/util/ReadlineConsole.java | 180 ----------- 3 files changed, 3 insertions(+), 185 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -140,7 +140,6 @@ - diff --git a/registry b/registry --- a/registry +++ b/registry @@ -39,10 +39,9 @@ #python.console=org.python.util.JLineConsole # To activate the featureless Jython console explicitly, choose: #python.console=org.python.core.PlainConsole -# By setting this to the name of a different console class, -# new console features can be enabled. For example: -#python.console=org.python.util.ReadlineConsole -#python.console.readlinelib=GnuReadline +# You may also set this to the name of a different console class in +# your classpath that extends PlainConsole. Note that +# org.python.util.ReadlineConsole has been removed in 2.7. # Setting this to a valid (Java) codec name will cause the console to use a # different encoding when reading commands from the console. diff --git a/src/org/python/util/ReadlineConsole.java b/src/org/python/util/ReadlineConsole.java deleted file mode 100644 --- a/src/org/python/util/ReadlineConsole.java +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2013 Jython Developers -package org.python.util; - -import java.io.EOFException; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; - -import org.gnu.readline.Readline; -import org.gnu.readline.ReadlineLibrary; -import org.python.core.PlainConsole; - -/** - * Uses: Java Readline to provide readline like - * functionality to its console through native readline support (either GNU Readline or Editline). - */ -public class ReadlineConsole extends PlainConsole { - - /** The longest we expect a console prompt to be (in encoded bytes) */ - public static final int MAX_PROMPT = 512; - /** Stream wrapping System.out in order to capture the last prompt. */ - private ConsoleOutputStream outWrapper; - /** Original System.out as sometimes we have to sneak one out. */ - private PrintStream originalSystemOut; - - /** - * Construct an instance of the console class specifying the character encoding. This encoding - * must be one supported by the JVM. The particular backing library loaded will be as specified - * by registry item python.console.readlinelib, or "Editline" by default. - *

- * Most of the initialisation is deferred to the {@link #install()} method so that any prior - * console can uninstall itself before we change system console settings and - * System.in. - * - * @param encoding name of a supported encoding or null for - * Charset.defaultCharset() - */ - public ReadlineConsole(String encoding) { - super(encoding); - /* - * Load the chosen native library. If it's not there, raise UnsatisfiedLinkError. We cannot - * fall back to Readline's Java mode since it reads from System.in, which would be pointless - * ... and fatal once we have replaced System.in with a wrapper on Readline. - */ - String backingLib = System.getProperty("python.console.readlinelib", "Editline"); - Readline.load(ReadlineLibrary.byName(backingLib)); - - /* - * The following is necessary to compensate for (a possible thinking error in) Readline's - * handling of the bytes returned from the library, and of the prompt. - */ - String name = encodingCharset.name(); - if (name.equals("ISO-8859-1") || name.equals("US-ASCII")) { - // Indicate that Readline's Latin fixation will work for this encoding - latin1 = null; - } else { - // We'll need the bytes-to-pointcode mapping - latin1 = Charset.forName("ISO-8859-1"); - } - } - - /** - * {@inheritDoc} - *

- * This implementation overrides that by setting System.in to a - * FilterInputStream object that wraps the configured console library, and wraps - * System.out in a stream that captures the prompt so the Readline library may re-use it. - */ - @Override - public void install() { - - // Complete the initialisation - Readline.initReadline("jython"); - - try { - // Force rebind of tab to insert a tab instead of complete - Readline.parseAndBind("tab: tab-insert"); - } catch (UnsupportedOperationException uoe) { - // parseAndBind not supported by this readline - } - - /* - * Wrap System.out in a special PrintStream that keeps a copy of the last incomplete line in case it - * turns out to be a console prompt. - */ - try { - originalSystemOut = System.out; - outWrapper = new ConsoleOutputStream(originalSystemOut, MAX_PROMPT); - System.setOut(new PrintStream(outWrapper, true, encoding)); - } catch (IOException e) { - throw new RuntimeException(e); - } - - // Replace System.in - FilterInputStream wrapper = new Stream(); - System.setIn(wrapper); - } - - /** - * Class to wrap the line-oriented interface to Readline with an InputStream that can replace - * System.in. - */ - protected class Stream extends ConsoleInputStream { - - /** Create a System.in replacement with Readline that adds Unix-like line endings */ - Stream() { - super(System.in, encodingCharset, EOLPolicy.ADD, LINE_SEPARATOR); - } - - @Override - protected CharSequence getLine() throws IOException, EOFException { - // Send cursor to start of line. - originalSystemOut.print('\r'); - // The prompt is the current partial output line. - CharSequence prompt = outWrapper.getPrompt(encodingCharset).toString(); - // Compensate for Readline.readline prompt handling - prompt = preEncode(prompt); - // Get the line from the console via the library - String line = Readline.readline(prompt.toString()); - // If Readline.readline really returned the line as typed, next would have been: - // return line==null ? "" : line; - return postDecode(line); - } - } - - /** - * Encode a prompt to bytes in the console encoding and represent these bytes as the point codes - * of a Java String. The actual GNU readline function expects a prompt string that is C char - * array in the console encoding, but the wrapper Readline.readline acts as if this - * encoding is always Latin-1. This transformation compensates by encoding correctly then - * representing those bytes as point codes. - * - * @param prompt to display via Readline.readline - * @return encoded form of prompt - */ - private CharSequence preEncode(CharSequence prompt) { - if (prompt == null || prompt.length() == 0) { - return ""; - } else if (latin1 == null) { - // Encoding is such that readline does the right thing - return prompt; - } else { - // Compensate for readline prompt handling - CharBuffer cb = CharBuffer.wrap(prompt); - ByteBuffer bb = encodingCharset.encode(cb); - return latin1.decode(bb).toString(); - } - } - - /** - * Decode the bytes argument (a return from code>Readline.readline) to the String - * actually entered at the console. The actual GNU readline function returns a C char array in - * the console encoding, but the wrapper Readline.readline acts as if this encoding - * is always Latin-1, and on this basis it gives us a Java String whose point codes are the - * encoded bytes. This method gets the bytes back, then decodes them correctly to a String. - * - * @param bytes encoded line (or null for an empty line) - * @return bytes recovered from the argument - */ - private CharSequence postDecode(String line) { - if (line == null) { - // Library returns null for an empty line - return ""; - } else if (latin1 == null) { - // Readline's assumed Latin-1 encoding will have produced the correct result - return line; - } else { - // We have to transcode the line - CharBuffer cb = CharBuffer.wrap(line); - ByteBuffer bb = latin1.encode(cb); - return encodingCharset.decode(bb).toString(); - } - } - - private final Charset latin1; - -} -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 19 21:41:35 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 19 Jan 2015 20:41:35 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_some_test=5Fcmd=5Fline?= =?utf-8?q?=5FScript_assertions?= Message-ID: <20150119204127.93201.78520@psf.io> https://hg.python.org/jython/rev/5e92dc1b75b4 changeset: 7540:5e92dc1b75b4 user: Indra Talip date: Mon Jan 19 13:41:21 2015 -0700 summary: Fix some test_cmd_line_Script assertions files: Lib/test/test_cmd_line_script.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -73,9 +73,9 @@ print 'Output from test script %r:' % script_name print data self.assertEqual(exit_code, 0) - printed_file = '__file__==%r' % expected_file - printed_argv0 = 'sys.argv[0]==%r' % expected_argv0 - printed_package = '__package__==%r' % expected_package + printed_file = '__file__==%r' % str(expected_file) + printed_argv0 = 'sys.argv[0]==%r' % str(expected_argv0) + printed_package = '__package__==%r' % (str(expected_package) if expected_package is not None else expected_package) if verbose: print 'Expected output:' print printed_file -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Jan 19 21:49:29 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 19 Jan 2015 20:49:29 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_pwd=2Egetpwuid_should_raise?= =?utf-8?q?_KeyError_with_out-of-range_uid_=28thanks_Nathaniel?= Message-ID: <20150119204917.93187.50237@psf.io> https://hg.python.org/jython/rev/d698dfc0b741 changeset: 7541:d698dfc0b741 user: Jim Baker date: Mon Jan 19 13:49:08 2015 -0700 summary: pwd.getpwuid should raise KeyError with out-of-range uid (thanks Nathaniel Kenmir) files: ACKNOWLEDGMENTS | 1 + Lib/pwd.py | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -145,6 +145,7 @@ Raphael Jolly Yuji Yamano Pekka Kl?rck + Nathaniel Kenmir Local Variables: mode: indented-text diff --git a/Lib/pwd.py b/Lib/pwd.py --- a/Lib/pwd.py +++ b/Lib/pwd.py @@ -50,7 +50,7 @@ See pwd.__doc__ for more on password database entries. """ if uid > sys.maxint or uid < 0: - raise KeyError + raise KeyError(uid) entry = _posix_impl.getpwuid(uid) if not entry: raise KeyError(uid) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 00:09:22 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 19 Jan 2015 23:09:22 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Adds_bytecode_notification_?= =?utf-8?q?mechanism?= Message-ID: <20150119230919.104126.33673@psf.io> https://hg.python.org/jython/rev/88209128cde8 changeset: 7542:88209128cde8 user: Jiwon Seo date: Mon Jan 19 16:08:45 2015 -0700 summary: Adds bytecode notification mechanism Callbacks can be registered/unregistered to be notified when bytecode is loaded, using API in jythonlib.bytecodetools. Merged from https://bitbucket.org/jython/jython/pull-request/41/adding-bytecode-notification-mechanism/ with minor changes by Jim Baker. files: ACKNOWLEDGMENTS | 1 + Lib/jythonlib.py | 1 + Lib/test/test_bytecodetools_jy.py | 107 ++++++++++ NEWS | 2 + src/org/python/compiler/LegacyCompiler.java | 5 - src/org/python/core/BytecodeLoader.java | 4 +- src/org/python/core/BytecodeNotification.java | 81 +++++++ src/org/python/core/CompilerFacade.java | 1 - src/org/python/core/PythonCodeBundle.java | 2 - src/org/python/modules/Setup.java | 1 + src/org/python/modules/_bytecodetools.java | 66 ++++++ 11 files changed, 262 insertions(+), 9 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -146,6 +146,7 @@ Yuji Yamano Pekka Kl?rck Nathaniel Kenmir + Jiwon Seo Local Variables: mode: indented-text diff --git a/Lib/jythonlib.py b/Lib/jythonlib.py --- a/Lib/jythonlib.py +++ b/Lib/jythonlib.py @@ -1,4 +1,5 @@ from _jythonlib import * +import _bytecodetools as bytecodetools # Convenience imports, since this is the most common case for using # jythonlib, especially with MapMaker diff --git a/Lib/test/test_bytecodetools_jy.py b/Lib/test/test_bytecodetools_jy.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_bytecodetools_jy.py @@ -0,0 +1,107 @@ +from test import test_support +from jythonlib import bytecodetools as tools +from java.util.concurrent import Callable +from org.python.core import Options + +import glob +import os.path +import sys +import tempfile +import unittest + + +class BytecodeCallbackTest(unittest.TestCase): + + def setUp(self): + self.count=0 + tools.clear() + + def assert_callback(self, name, byte, klass): + self.count+=1 + self.assertEqual(name, klass.name) + + def test_register(self): + tools.register(self.assert_callback) + eval("42+1") + + def test_unregister(self): + self.count=0 + tools.register(self.assert_callback) + eval("42+1") + self.assertEqual(self.count, 1) + + tools.unregister(self.assert_callback) + eval("42+1") + self.assertEqual(self.count, 1) + + def faulty_callback(self, name, byte, klass): + raise Exception("test exception") + def faulty_callback2(self, name, byte, klass, bogus): + return + + def test_faulty_callback(self): + import java.lang.System as Sys + import java.io.PrintStream as PrintStream + import java.io.OutputStream as OutputStream + + class NullOutputStream(OutputStream): + def write(self, b): pass + def write(self, buf, offset, len): pass + + syserr = Sys.err + Sys.setErr(PrintStream(NullOutputStream())) + + tools.register(self.faulty_callback) + tools.register(self.assert_callback) + tools.register(self.faulty_callback2) + self.count=0 + try: + eval("42+1") + finally: + self.assertTrue(tools.unregister(self.faulty_callback)) + self.assertTrue(tools.unregister(self.faulty_callback2)) + self.assertTrue(tools.unregister(self.assert_callback)) + Sys.setErr(syserr) + self.assertEqual(self.count, 1) + + +class ProxyDebugDirectoryTest(unittest.TestCase): + """ProxyDebugDirectory used to be the only way to save proxied classes""" + + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + + def tearDown(self): + test_support.rmtree(self.tmpdir) + + def test_set_debug_directory(self): + """Verify that proxy debug directory can be set at runtime""" + self.assertIs(Options.proxyDebugDirectory, None) + Options.proxyDebugDirectory = self.tmpdir + + class C(Callable): + def call(self): + return 47 + + self.assertEqual(C().call(), 47) + proxy_dir = os.path.join(self.tmpdir, "org", "python", "proxies") + # If test script is run outside of regrtest, the first path is used; + # otherwise the second + proxy_classes = glob.glob(os.path.join(proxy_dir, "*.class")) + \ + glob.glob(os.path.join(proxy_dir, "test", "*.class")) + self.assertEqual(len(proxy_classes), 1, "Only one proxy class is generated") + self.assertRegexpMatches( + proxy_classes[0], + r'\$C\$\d+.class$') + + +def test_main(): + test_support.run_unittest( + BytecodeCallbackTest, + ProxyDebugDirectoryTest + ) + + +if __name__ == '__main__': + test_main() + diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -52,6 +52,8 @@ - CPython's _json.c was ported to Java to speed up JSON encoding/decoding - Upgraded third party libraries - Initial support for ensurepip module + - Callbacks can be registered/unregistered to be notified when + bytecode is loaded, using jythonlib.bytecodetools Potentially backwards breaking changes, removing silent errors: diff --git a/src/org/python/compiler/LegacyCompiler.java b/src/org/python/compiler/LegacyCompiler.java --- a/src/org/python/compiler/LegacyCompiler.java +++ b/src/org/python/compiler/LegacyCompiler.java @@ -53,11 +53,6 @@ } } - public void saveCode(String directory) throws Exception { - // FIXME: this is slightly broken, it should use the directory - Py.saveClassFile(name, ostream()); - } - private ByteArrayOutputStream ostream() throws Exception { if (ostream == null) { ostream = new ByteArrayOutputStream(); diff --git a/src/org/python/core/BytecodeLoader.java b/src/org/python/core/BytecodeLoader.java --- a/src/org/python/core/BytecodeLoader.java +++ b/src/org/python/core/BytecodeLoader.java @@ -34,7 +34,9 @@ } catch (SecurityException e) { } } - return loader.loadClassFromBytes(name, data); + Class c = loader.loadClassFromBytes(name, data); + BytecodeNotification.notify(name, data, c); + return c; } /** diff --git a/src/org/python/core/BytecodeNotification.java b/src/org/python/core/BytecodeNotification.java new file mode 100644 --- /dev/null +++ b/src/org/python/core/BytecodeNotification.java @@ -0,0 +1,81 @@ +package org.python.core; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.Collections; +import java.io.ByteArrayOutputStream; + +/** + * Notifies registered callbacks if new bytecode is loaded. + */ +public class BytecodeNotification { + /** + * Interface for callbacks. + * Notifies the name of the loaded class, raw bytes of the class, + * and the Java class object. + */ + public interface Callback { + public void notify(String name, byte[] bytes, Class c); + } + + /** + * The following list stores register callback objects. + * The list is shared among the PySystemState objects + * if there are multiple instances. + */ + private static List callbacks = new CopyOnWriteArrayList(); + + static { + // Maintain legacy behavior + register(new Callback() { + public void notify(String name, byte[] bytes, Class c) { + if (Options.proxyDebugDirectory == null || + (!name.startsWith("org.python.pycode.") && + !name.startsWith("org.python.proxies."))) { + return; + } + ByteArrayOutputStream ostream = new ByteArrayOutputStream(bytes.length); + ostream.write(bytes, 0, bytes.length); + Py.saveClassFile(name, ostream); + } + }); + } + + /** + * Registers the class as a callback + * + * @param n the callback object + */ + public static void register(Callback n) { callbacks.add(n); } + + /** + * Unregisters the callback object + * + * @param n the callback object + * @return true if successfully removed and + * false if the callback object was not registered + */ + public static boolean unregister(Callback n) { return callbacks.remove(n); } + + /** + * Clears all the registered callbacks + */ + public static void clear() { callbacks.clear(); } + + /** + * Notifies that the new bytecode to the registered callbacks + * + * @param name the name of the class of the new bytecode + * @param data raw byte data of the class + * @param class Java class object of the new bytecode + */ + public static void notify(String name, byte[] data, Class klass) { + for (Callback c:callbacks) { + try { + c.notify(name, data, klass); + } catch (Exception e) { + Py.writeWarning("BytecodeNotification", "Exception from callback:"+e); + } + } + } +} diff --git a/src/org/python/core/CompilerFacade.java b/src/org/python/core/CompilerFacade.java --- a/src/org/python/core/CompilerFacade.java +++ b/src/org/python/core/CompilerFacade.java @@ -30,7 +30,6 @@ try { PythonCodeBundle bundle = compiler.compile(node, name, filename, linenumbers, printResults, cflags); - bundle.saveCode(Options.proxyDebugDirectory); return bundle.loadCode(); } catch (Throwable t) { throw ParserFacade.fixParseError(null, t, filename); diff --git a/src/org/python/core/PythonCodeBundle.java b/src/org/python/core/PythonCodeBundle.java --- a/src/org/python/core/PythonCodeBundle.java +++ b/src/org/python/core/PythonCodeBundle.java @@ -8,6 +8,4 @@ void writeTo(OutputStream stream) throws Exception; - void saveCode(String directory) throws Exception; - } diff --git a/src/org/python/modules/Setup.java b/src/org/python/modules/Setup.java --- a/src/org/python/modules/Setup.java +++ b/src/org/python/modules/Setup.java @@ -28,6 +28,7 @@ public static String[] builtinModules = { "_ast:org.python.antlr.ast.AstModule", + "_bytecodetools", "_codecs", "_collections:org.python.modules._collections.Collections", "_csv:org.python.modules._csv._csv", diff --git a/src/org/python/modules/_bytecodetools.java b/src/org/python/modules/_bytecodetools.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/_bytecodetools.java @@ -0,0 +1,66 @@ +package org.python.modules; + +import org.python.core.BytecodeNotification; +import org.python.core.PyObject; +import org.python.core.Py; + +/** + * BytecodeTools provides tools for generated JVM bytecode. + *

+ * This module supports registering a python callback function + * to be notified when new bytecode is loaded. + * see also core/BytecodeNotification.java + */ +public class _bytecodetools { + public static final String __doc__ = + "Provides utilities for generated bytecode.\n"; + + public static final String __name__ = "BytecodeTools"; + + static class _Callback implements BytecodeNotification.Callback { + PyObject callback; + + public _Callback(PyObject callback) { + this.callback = callback; + } + + public void notify(String name, byte[] bytes, Class c) { + callback.__call__(Py.java2py(name), Py.java2py(bytes), Py.java2py(c)); + } + + public int hashCode() { + return callback.hashCode(); + } + + public boolean equals(Object other) { + if (!(other instanceof _Callback)) return false; + _Callback that = (_Callback) other; + return callback.equals(that.callback); + } + } + + /** + * Registers a python callback function that will be notified on bytecode loading. + * + * @param callback a Python callback function + */ + public static void register(final PyObject callback) { + BytecodeNotification.register(new _Callback(callback)); + } + + /** + * Unregisters a python callback function. + * + * @param callback a Python callback function + */ + public static boolean unregister(final PyObject callback) { + return BytecodeNotification.unregister(new _Callback(callback)); + } + + /** + * Clears all the registered callbacks. + */ + public static void clear() { + BytecodeNotification.clear(); + } +} -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_abs=28-0=2E0=29_should_be_0?= =?utf-8?q?=2E0?= Message-ID: <20150120220713.118078.6817@psf.io> https://hg.python.org/jython/rev/dac0a2a4b370 changeset: 7544:dac0a2a4b370 user: Jeff Allen date: Thu Jan 08 20:05:41 2015 +0000 summary: abs(-0.0) should be 0.0 files: Lib/test/test_float_jy.py | 7 +++++++ src/org/python/core/PyFloat.java | 5 +---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_float_jy.py b/Lib/test/test_float_jy.py --- a/Lib/test/test_float_jy.py +++ b/Lib/test/test_float_jy.py @@ -85,6 +85,13 @@ self.assert_(type(float('inf')), float) self.assertRaises(OverflowError, long, float('Infinity')) + def test_minus_zero(self): + # Some operations confused by -0.0 + mz = float('-0.0') + self.assertEquals(mz, 0.) + self.assertEquals(repr(mz)[0], '-') + self.assertEquals(repr(abs(mz))[0], '0') + def test_float_none(self): self.assertRaises(TypeError, float, None) diff --git a/src/org/python/core/PyFloat.java b/src/org/python/core/PyFloat.java --- a/src/org/python/core/PyFloat.java +++ b/src/org/python/core/PyFloat.java @@ -839,10 +839,7 @@ @ExposedMethod(doc = BuiltinDocs.float___abs___doc) final PyObject float___abs__() { - if (getValue() < 0) { - return float___neg__(); - } - return float___float__(); + return new PyFloat(Math.abs(getValue())); } @Override -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Re-work_cmath=2Elog=2C_and_?= =?utf-8?q?cmath=2Elog10_for_accuracy_and_corner_cases=2E?= Message-ID: <20150120220714.69926.29146@psf.io> https://hg.python.org/jython/rev/0c240eade776 changeset: 7545:0c240eade776 user: Jeff Allen date: Fri Jan 09 23:20:20 2015 +0000 summary: Re-work cmath.log, and cmath.log10 for accuracy and corner cases. files: src/org/python/modules/cmath.java | 158 +++++++++++++---- src/org/python/modules/math.java | 2 +- 2 files changed, 120 insertions(+), 40 deletions(-) diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -23,6 +23,9 @@ /** ln({@link Double#MAX_VALUE}) or a little less */ private static final double NEARLY_LN_DBL_MAX = 709.4361393; + /** log10e (Ref: Abramowitz & Stegun [1972], p3). */ + private static final double LOG10E = 0.43429448190325182765; + private static PyComplex c_prodi(PyComplex x) { return (PyComplex)x.__mul__(i); } @@ -204,18 +207,6 @@ return exceptNaN(new PyComplex(u, v), zz); } - public static PyComplex log(PyObject in) { - PyComplex x = complexFromPyObject(in); - if (isNaN(x)) { - if (Double.isInfinite(x.real) || Double.isInfinite(x.imag)) { - return new PyComplex(Double.POSITIVE_INFINITY, Double.NaN); - } else { - return PyComplex.NaN; - } - } - return new PyComplex(Math.log(abs(x)), Math.atan2(x.imag, x.real)); - } - public static double phase(PyObject in) { PyComplex x = complexFromPyObject(in); return Math.atan2(x.imag, x.real); @@ -269,36 +260,125 @@ return Double.isNaN(x.real) || Double.isNaN(x.imag); } - public static PyComplex log10(PyObject in) { - PyComplex x = complexFromPyObject(in); - if (isNaN(x)) { - if (Double.isInfinite(x.real) || Double.isInfinite(x.imag)) { - return new PyComplex(Double.POSITIVE_INFINITY, Double.NaN); + /** + * Returns the natural logarithm of w. + * + * @param w + * @return ln w + */ + public static PyComplex log(PyObject w) { + PyComplex ww = complexFromPyObject(w); + double u = ww.real, v = ww.imag; + // The real part of the result is the log of the magnitude. + double lnr = logHypot(u, v); + // The imaginary part of the result is the arg. This may result in a nan. + double theta = Math.atan2(v, u); + PyComplex z = new PyComplex(lnr, theta); + return exceptNaN(z, ww); + } + + /** + * Returns the common logarithm of w (base 10 logarithm). + * + * @param w + * @return log10w + */ + public static PyComplex log10(PyObject w) { + PyComplex ww = complexFromPyObject(w); + double u = ww.real, v = ww.imag; + // The expression is the same as for base e, scaled in magnitude. + double logr = logHypot(u, v) * LOG10E; + double theta = Math.atan2(v, u) * LOG10E; + PyComplex z = new PyComplex(logr, theta); + return exceptNaN(z, ww); + } + + /** + * Returns the logarithm of w to the given base. If the base is not specified, returns + * the natural logarithm of w. There is one branch cut, from 0 along the negative real + * axis to -∞, continuous from above. + * + * @param w + * @param b + * @return logbw + */ + public static PyComplex log(PyObject w, PyObject b) { + PyComplex ww = complexFromPyObject(w), bb = complexFromPyObject(b), z; + double u = ww.real, v = ww.imag, br = bb.real, bi = bb.imag, x, y; + // Natural log of w is (x,y) + x = logHypot(u, v); + y = Math.atan2(v, u); + + if (bi != 0. || br <= 0.) { + // Complex or negative real base requires complex log: general case. + PyComplex lnb = log(bb); + z = (PyComplex)(new PyComplex(x, y)).__div__(lnb); + + } else { + // Real positive base: frequent case. (b = inf or nan ends up here too.) + double lnb = Math.log(br); + z = new PyComplex(x / lnb, y / lnb); + } + + return exceptNaN(z, ww); + } + + /** + * Helper function for the log of a complex number, dealing with the log magnitude, and without + * intermediate overflow or underflow. It returns ln r, where r2 = + * u2+v2. To do this it computes + * ½ln(u2+v2). Special cases are handled as follows: + *

    + *
  • if u or v is NaN, it returns NaN
  • + *
  • if u or v is infinite, it returns positive infinity
  • + *
  • if u and v are both zero, it raises a ValueError
  • + *
+ * We have this function instead of Math.log(Math.hypot(u,v)) because a valid + * result is still possible even when hypot(u,v) overflows, and because there's no + * point in taking a square root when a log is to follow. + * + * @param u + * @param v + * @return ½ln(u2+v2) + */ + private static double logHypot(double u, double v) { + + if (Double.isInfinite(u) || Double.isInfinite(v)) { + return Double.POSITIVE_INFINITY; + + } else { + // Cannot overflow, but if u=v=0 will return -inf. + int scale = 0, ue = Math.getExponent(u), ve = Math.getExponent(v); + double lnr; + + if (ue < -511 && ve < -511) { + // Both u and v are too small to square, or zero. (Just one would be ok.) + scale = 600; + } else if (ue > 510 || ve > 510) { + // One of these is too big to square and double (or is nan or inf). + scale = -600; + } + + if (scale == 0) { + // Normal case: there is no risk of overflow or log of zero. + lnr = 0.5 * Math.log(u * u + v * v); } else { - return PyComplex.NaN; + // We must work with scaled values, us = u * 2**n etc.. + double us = Math.scalb(u, scale); + double vs = Math.scalb(v, scale); + // rs**2 = r**2 * 2**2n + double rs2 = us * us + vs * vs; + // So ln(r) = ln(u**2+v**2)/2 = ln(us**2+vs**2)/2 - n ln(2) + lnr = 0.5 * Math.log(rs2) - scale * math.LN2; + } + + // (u,v) = 0 leads to ln(r) = -inf, but that's a domain error + if (lnr == Double.NEGATIVE_INFINITY) { + throw math.mathDomainError(); + } else { + return lnr; } } - double l = abs(x); - return new PyComplex(math.log10(new PyFloat(l)), Math.atan2(x.imag, x.real) - / Math.log(10.0)); - } - - public static PyComplex log(PyObject in, PyObject base) { - return log(complexFromPyObject(in), complexFromPyObject(base)); - } - - public static PyComplex log(PyComplex x, PyComplex base) { - if (isNaN(x)) { - if (Double.isInfinite(x.real) || Double.isInfinite(x.imag)) { - return new PyComplex(Double.POSITIVE_INFINITY, Double.NaN); - } else { - return PyComplex.NaN; - } - } - double l = abs(x); - PyComplex log_base = log(base); - return (PyComplex)new PyComplex(math.log(new PyFloat(l)), Math.atan2(x.imag, x.real)) - .__div__(log_base); } public static PyComplex sin(PyObject in) { diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java --- a/src/org/python/modules/math.java +++ b/src/org/python/modules/math.java @@ -24,7 +24,7 @@ private static final double MINUS_ONE = -1.0; private static final double TWO = 2.0; private static final double EIGHT = 8.0; - private static final double LN2 = 0.693147180559945309417232121458; // Ref OEIS A002162 + static final double LN2 = 0.693147180559945309417232121458; // Ref OEIS A002162 private static final double INF = Double.POSITIVE_INFINITY; private static final double NINF = Double.NEGATIVE_INFINITY; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Re-work_cmath=2Etan_and_cma?= =?utf-8?q?th=2Etanh_for_accuracy_and_corner_cases=2E?= Message-ID: <20150120220714.103305.51156@psf.io> https://hg.python.org/jython/rev/4a24e60cb215 changeset: 7548:4a24e60cb215 user: Jeff Allen date: Sun Jan 11 18:35:01 2015 +0000 summary: Re-work cmath.tan and cmath.tanh for accuracy and corner cases. files: src/org/python/modules/cmath.java | 124 ++++++++++++++--- 1 files changed, 98 insertions(+), 26 deletions(-) diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -694,36 +694,108 @@ } } - public static PyComplex tan(PyObject in) { - PyComplex x = complexFromPyObject(in); - - double sr = Math.sin(x.real); - double cr = Math.cos(x.real); - double shi = math.sinh(x.imag); - double chi = math.cosh(x.imag); - double rs = sr * chi; - double is = cr * shi; - double rc = cr * chi; - double ic = -sr * shi; - double d = rc * rc + ic * ic; - - return new PyComplex(((rs * rc) + (is * ic)) / d, ((is * rc) - (rs * ic)) / d); + /** + * Return the tangent of z. + * + * @param z + * @return tan z + */ + public static PyComplex tan(PyObject z) { + return tanOrTanh(complexFromPyObject(z), false); } - public static PyComplex tanh(PyObject in) { - PyComplex x = complexFromPyObject(in); + /** + * Return the hyperbolic tangent of z. + * + * @param z + * @return tanh z + */ + public static PyComplex tanh(PyObject z) { + return tanOrTanh(complexFromPyObject(z), true); + } - double si = Math.sin(x.imag); - double ci = Math.cos(x.imag); - double shr = math.sinh(x.real); - double chr = math.cosh(x.real); - double rs = ci * shr; - double is = si * chr; - double rc = ci * chr; - double ic = si * shr; - double d = rc * rc + ic * ic; + /** + * Helper to compute either tan z or tanh z. The expression used is: + *

+ * tanh(x+iy) = (sinh x cosh x + i sin y cos y) / + * (sinh2x + cos2y) + *

+ * A simplification is made for x sufficiently large that e2|x|≫1 that + * deals satisfactorily with large or infinite x. When computing tan, we evaluate + * i tan iz instead, and the approximation applies to + * e2|y|≫1. + * + * @param z + * @param h true to compute tanh z, false to compute tan + * z. + * @return tan or tanh z + */ + private static PyComplex tanOrTanh(PyComplex z, boolean h) { + double x, y, u, v, s; + PyComplex w; - return new PyComplex(((rs * rc) + (is * ic)) / d, ((is * rc) - (rs * ic)) / d); + if (h) { + // We compute w = tanh(z). Let w = u + iv and z = x + iy. + x = z.real; + y = z.imag; + // Then the function body computes tanh(x+iy), according to: + // s = sinh**2 x + cos**2 y + // u = sinh x cosh x / s, + // v = sin y cos y / s, + // And we return w = u + iv. + } else { + // We compute w = tan(z). Unusually, let z = y - ix, so x + iy = iz. + y = z.real; + x = -z.imag; + // Then the function body computes tanh(x+iy) = tanh(iz) = i tan(z) as before, + // but we finally return w = v - iu = tan(z). + } + + if (y == 0.) { + // Real argument for tanh (or imaginary for tan). + u = Math.tanh(x); + // v is zero but follows the sign of y (which could be -0.0). + v = y; + + } else if (x == 0. && !Double.isNaN(y)) { + // Imaginary argument for tanh (or real for tan): imaginary result at this point. + v = Math.tan(y); // May raise domain error + // u is zero but follows sign of x (which could be -0.0). + u = x; + + } else { + // The trig calls will not throw, although if y is infinite, they return nan. + double cosy = Math.cos(y), siny = Math.sin(y), absx = Math.abs(x); + + if (absx > ATLEAST_27LN2) { + // e**2x is much greater than 1: exponential approximation to sinh and cosh. + s = 0.25 * Math.exp(2 * absx); + u = Math.copySign(1., x); + if (s == Double.POSITIVE_INFINITY) { + // Either x is inf or 2x is large enough to overflow exp(). v=0, but signed: + v = Math.copySign(0., siny * cosy); + } else { + v = siny * cosy / s; + } + + } else { + // Normal case: possible overflow in s near (x,y) = (0,pi/2) is harmless. + double sinhx = Math.sinh(x), coshx = Math.cosh(x); + s = sinhx * sinhx + cosy * cosy; + u = sinhx * coshx / s; + v = siny * cosy / s; + } + } + + // Compose the result w according to whether we're computing tan(z) or tanh(z). + if (h) { + w = new PyComplex(u, v); // w = u + iv = tanh(x+iy). + } else { + w = new PyComplex(v, -u); // w = v - iu = tan(y-ix) = tan(z) + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(w, z); } /** -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_cmath=2Eexp_conforms_to_tes?= =?utf-8?q?t=5Fcmath?= Message-ID: <20150120220713.103315.74643@psf.io> https://hg.python.org/jython/rev/367557fb6120 changeset: 7543:367557fb6120 parent: 7510:44cfecd93257 user: Jeff Allen date: Thu Jan 08 19:37:26 2015 +0000 summary: cmath.exp conforms to test_cmath ... and in the remotest corners of the complex plane. files: src/org/python/modules/cmath.java | 108 +++++++++++++++++- src/org/python/modules/math.java | 6 +- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -2,6 +2,7 @@ import org.python.core.Py; import org.python.core.PyComplex; +import org.python.core.PyException; import org.python.core.PyFloat; import org.python.core.PyInstance; import org.python.core.PyObject; @@ -19,6 +20,8 @@ /** 2 (Ref: Abramowitz & Stegun [1972], p2). */ private static final double ROOT_HALF = 0.70710678118654752440; + /** ln({@link Double#MAX_VALUE}) or a little less */ + private static final double NEARLY_LN_DBL_MAX = 709.4361393; private static PyComplex c_prodi(PyComplex x) { return (PyComplex)x.__mul__(i); @@ -140,10 +143,65 @@ * math.sinh(x.real)); } - public static PyComplex exp(PyObject in) { - PyComplex x = complexFromPyObject(in); - double l = Math.exp(x.real); - return new PyComplex(l * Math.cos(x.imag), l * Math.sin(x.imag)); + /** + * Return the exponential value ez. + * + * @param z + * @return ez + */ + public static PyComplex exp(PyObject z) { + PyComplex zz = complexFromPyObject(z); + double x = zz.real, y = zz.imag, r, u, v; + /* + * This has a lot of corner-cases, and some of them make little sense sense, but it matches + * CPython and passes the regression tests. + */ + if (y == 0.) { + // Real value: use a real solution. (This may raise a range error.) + u = math.exp(x); + // v follows sign of y. + v = y; + + } else { + // The trig calls will not throw, although if y is infinite, they return nan. + double cosy = Math.cos(y), siny = Math.sin(y); + + if (x == Double.NEGATIVE_INFINITY) { + // w = (0,0) but "signed" by the direction cosines (even in they are nan). + u = Math.copySign(0., cosy); + v = Math.copySign(0., siny); + + } else if (x == Double.POSITIVE_INFINITY) { + if (!Double.isNaN(cosy)) { + // w = (inf,inf), but "signed" by the direction cosines. + u = Math.copySign(x, cosy); + v = Math.copySign(x, siny); + } else { + // Provisionally w = (inf,nan), which will raise domain error if y!=nan. + u = x; + v = Double.NaN; + } + + } else if (x > NEARLY_LN_DBL_MAX) { + // r = e**x would overflow but maybe not r*cos(y) and r*sin(y). + r = Math.exp(x - 1); // = r / e + u = r * cosy * Math.E; + v = r * siny * Math.E; + if (Double.isInfinite(u) || Double.isInfinite(v)) { + // A finite x gave rise to an infinite u or v. + throw math.mathRangeError(); + } + + } else { + // Normal case, without risk of overflow. + // Compute r = exp(x), and return w = u + iv = r (cos(y) + i*sin(y)) + r = Math.exp(x); + u = r * cosy; + v = r * siny; + } + } + // If that generated a nan, and there wasn't one in the argument, raise domain error. + return exceptNaN(new PyComplex(u, v), zz); } public static PyComplex log(PyObject in) { @@ -396,4 +454,46 @@ return new PyComplex(((rs * rc) + (is * ic)) / d, ((is * rc) - (rs * ic)) / d); } + + /** + * Turn a NaN result into a thrown ValueError, a math domain error, if + * the original argument was not itself NaN. A PyComplex is a + * NaN if either component is a NaN. + * + * @param result to return (if we return) + * @param arg to include in check + * @return result if arg was NaN or result was not + * NaN + * @throws PyException (ValueError) if result was NaN and + * arg was not NaN + */ + private static PyComplex exceptNaN(PyComplex result, PyComplex arg) throws PyException { + if ((Double.isNaN(result.real) || Double.isNaN(result.imag)) + && !(Double.isNaN(arg.real) || Double.isNaN(arg.imag))) { + throw math.mathDomainError(); + } else { + return result; + } + } + + /** + * Turn an infinite result into a thrown OverflowError, a math range error, if the + * original argument was not itself infinite. A PyComplex is infinite if either + * component is infinite. + * + * @param result to return (if we return) + * @param arg to include in check + * @return result if arg was infinite or result was not infinite + * @throws PyException (ValueError) if result was infinite and arg was + * not infinite + */ + private static PyComplex exceptInf(PyComplex result, PyComplex arg) { + if ((Double.isInfinite(result.real) || Double.isInfinite(result.imag)) + && !(Double.isInfinite(arg.real) || Double.isInfinite(arg.imag))) { + throw math.mathRangeError(); + } else { + return result; + } + } + } diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java --- a/src/org/python/modules/math.java +++ b/src/org/python/modules/math.java @@ -515,7 +515,7 @@ * * @return ValueError("math domain error") */ - private static PyException mathDomainError() { + static PyException mathDomainError() { return Py.ValueError("math domain error"); } @@ -524,7 +524,7 @@ * * @return OverflowError("math range error") */ - private static PyException mathRangeError() { + static PyException mathRangeError() { return Py.OverflowError("math range error"); } @@ -575,7 +575,7 @@ */ private static double exceptInf(double result, double arg) { if (Double.isInfinite(result) && !Double.isInfinite(arg)) { - throw Py.OverflowError("math range error"); + throw mathRangeError(); } else { return result; } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Re-work_cmath=2Ecos_and_cma?= =?utf-8?q?th=2Ecosh_for_accuracy_and_corner_cases=2E?= Message-ID: <20150120220714.69922.35079@psf.io> https://hg.python.org/jython/rev/1bcc508b734a changeset: 7547:1bcc508b734a user: Jeff Allen date: Sat Jan 10 23:25:02 2015 +0000 summary: Re-work cmath.cos and cmath.cosh for accuracy and corner cases. This includes changes to cmath_testcases.txt, and its generator, so that reference results that are ostensibly real have -0.0 as their imaginary part where cmath should. (Only cos and cosh affected so far.) files: Lib/test/cmath_testcases.txt | 30 ++-- Misc/make_cmath_testcases.py | 14 +- src/org/python/modules/cmath.java | 119 +++++++++++++++-- 3 files changed, 131 insertions(+), 32 deletions(-) diff --git a/Lib/test/cmath_testcases.txt b/Lib/test/cmath_testcases.txt --- a/Lib/test/cmath_testcases.txt +++ b/Lib/test/cmath_testcases.txt @@ -1750,15 +1750,15 @@ cosh0053 cosh 0.0003 0.0 -> 1.0000000450000003375 0.0 cosh0054 cosh 0.2 0.0 -> 1.0200667556190758485 0.0 cosh0055 cosh 1.0 0.0 -> 1.5430806348152437785 0.0 -cosh0056 cosh -1e-18 0.0 -> 1.0 0.0 -cosh0057 cosh -0.0003 0.0 -> 1.0000000450000003375 0.0 -cosh0058 cosh -1.0 0.0 -> 1.5430806348152437785 0.0 +cosh0056 cosh -1e-18 0.0 -> 1.0 -0.0 +cosh0057 cosh -0.0003 0.0 -> 1.0000000450000003375 -0.0 +cosh0058 cosh -1.0 0.0 -> 1.5430806348152437785 -0.0 cosh0059 cosh 1.3169578969248168 0.0 -> 2.0000000000000001504 0.0 -cosh0060 cosh -1.3169578969248168 0.0 -> 2.0000000000000001504 0.0 +cosh0060 cosh -1.3169578969248168 0.0 -> 2.0000000000000001504 -0.0 cosh0061 cosh 17.328679513998633 0.0 -> 16777216.000000021938 0.0 cosh0062 cosh 18.714973875118524 0.0 -> 67108864.000000043662 0.0 cosh0063 cosh 709.7827 0.0 -> 8.9883497833190073272e+307 0.0 -cosh0064 cosh -709.7827 0.0 -> 8.9883497833190073272e+307 0.0 +cosh0064 cosh -709.7827 0.0 -> 8.9883497833190073272e+307 -0.0 -- special values cosh1000 cosh 0.0 0.0 -> 1.0 0.0 @@ -2071,20 +2071,20 @@ cos0023 cos 0.45124351152540226 1.6992693993812158 -> 2.543477948972237 -1.1528193694875477 -- Additional real values (Jython) -cos0050 cos 1e-150 0.0 -> 1.0 0.0 -cos0051 cos 1e-18 0.0 -> 1.0 0.0 -cos0052 cos 1e-09 0.0 -> 0.9999999999999999995 0.0 -cos0053 cos 0.0003 0.0 -> 0.9999999550000003375 0.0 -cos0054 cos 0.2 0.0 -> 0.98006657784124162892 0.0 -cos0055 cos 1.0 0.0 -> 0.5403023058681397174 0.0 +cos0050 cos 1e-150 0.0 -> 1.0 -0.0 +cos0051 cos 1e-18 0.0 -> 1.0 -0.0 +cos0052 cos 1e-09 0.0 -> 0.9999999999999999995 -0.0 +cos0053 cos 0.0003 0.0 -> 0.9999999550000003375 -0.0 +cos0054 cos 0.2 0.0 -> 0.98006657784124162892 -0.0 +cos0055 cos 1.0 0.0 -> 0.5403023058681397174 -0.0 cos0056 cos -1e-18 0.0 -> 1.0 0.0 cos0057 cos -0.0003 0.0 -> 0.9999999550000003375 0.0 cos0058 cos -1.0 0.0 -> 0.5403023058681397174 0.0 -cos0059 cos 1.0471975511965976 0.0 -> 0.50000000000000009945 0.0 -cos0060 cos 2.5707963267948966 0.0 -> -0.84147098480789647357 0.0 +cos0059 cos 1.0471975511965976 0.0 -> 0.50000000000000009945 -0.0 +cos0060 cos 2.5707963267948966 0.0 -> -0.84147098480789647357 -0.0 cos0061 cos -2.5707963267948966 0.0 -> -0.84147098480789647357 0.0 -cos0062 cos 18 0.0 -> 0.66031670824408014482 0.0 -cos0063 cos 18.0 0.0 -> 0.66031670824408014482 0.0 +cos0062 cos 18 0.0 -> 0.66031670824408014482 -0.0 +cos0063 cos 18.0 0.0 -> 0.66031670824408014482 -0.0 -- special values cos1000 cos -0.0 0.0 -> 1.0 0.0 diff --git a/Misc/make_cmath_testcases.py b/Misc/make_cmath_testcases.py --- a/Misc/make_cmath_testcases.py +++ b/Misc/make_cmath_testcases.py @@ -103,14 +103,24 @@ } def generate_cases() : - fmt = "{}{:04d} {} {!r} 0.0 -> {} 0.0" + fmt = "{}{:04d} {} {!r} 0.0 -> {} {!r}" for fn in sorted(cases_to_generate.keys()): print "-- Additional real values (Jython)" count, xlist = cases_to_generate[fn] for x in xlist: + # Compute the function (in the reference library) func = getattr(mpmath, fn) y = func(x) - print fmt.format(fn, count, fn, x, mpmath.nstr(y, 20) ) + # For the benefit of cmath tests, get the sign of imaginary zero right + zero = 0.0 + if math.copysign(1., x) > 0.: + if fn=='cos' : + zero = -0.0 + else : + if fn=='cosh' : + zero = -0.0 + # Output one test case at sufficient precision + print fmt.format(fn, count, fn, x, mpmath.nstr(y, 20), zero ) count += 1 def test_main(): diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -142,16 +142,105 @@ return (PyComplex)half.__mul__(log(one.__add__(x).__div__(one.__sub__(x)))); } - public static PyComplex cos(PyObject in) { - PyComplex x = complexFromPyObject(in); - return new PyComplex(Math.cos(x.real) * math.cosh(x.imag), -Math.sin(x.real) - * math.sinh(x.imag)); + /** + * Return the cosine of z. + * + * @param z + * @return cos z + */ + public static PyComplex cos(PyObject z) { + return cosOrCosh(complexFromPyObject(z), false); } - public static PyComplex cosh(PyObject in) { - PyComplex x = complexFromPyObject(in); - return new PyComplex(Math.cos(x.imag) * math.cosh(x.real), Math.sin(x.imag) - * math.sinh(x.real)); + /** + * Return the hyperbolic cosine of z. + * + * @param z + * @return cosh z + */ + public static PyComplex cosh(PyObject z) { + return cosOrCosh(complexFromPyObject(z), true); + } + + /** + * Helper to compute either cos z or cosh z. + * + * @param z + * @param h true to compute cosh z, false to compute cos + * z. + * @return + */ + private static PyComplex cosOrCosh(PyComplex z, boolean h) { + double x, y, u, v; + PyComplex w; + + if (h) { + // We compute w = cosh(z). Let w = u + iv and z = x + iy. + x = z.real; + y = z.imag; + // Then the function body computes cosh(x+iy), according to: + // u = cosh(x) cos(y), + // v = sinh(x) sin(y), + // And we return w = u + iv. + } else { + // We compute w = sin(z). Unusually, let z = y - ix, so x + iy = iz. + y = z.real; + x = -z.imag; + // Then the function body computes cosh(x+iy) = cosh(iz) = cos(z) as before. + } + + if (y == 0.) { + // Real argument for cosh (or imaginary for cos): use real library. + u = math.cosh(x); // This will raise a range error on overflow. + // v is zero but follows the sign of x*y (in which y could be -0.0). + v = Math.copySign(1., x) * y; + + } else if (x == 0.) { + // Imaginary argument for cosh (or real for cos): imaginary result at this point. + u = Math.cos(y); + // v is zero but follows the sign of x*y (in which x could be -0.0). + v = x * Math.copySign(1., y); + + } else { + + // The trig calls will not throw, although if y is infinite, they return nan. + double cosy = Math.cos(y), siny = Math.sin(y), absx = Math.abs(x); + + if (absx == Double.POSITIVE_INFINITY) { + if (!Double.isNaN(cosy)) { + // w = (inf,inf), but "rotated" by the direction cosines. + u = absx * cosy; + v = x * siny; + } else { + // Provisionally w = (inf,nan), which will raise domain error if y!=nan. + u = absx; + v = Double.NaN; + } + + } else if (absx > ATLEAST_27LN2) { + // Use 0.5*e**x approximation. This is also the region where we risk overflow. + double r = Math.exp(absx - 2.); + // r approximates 2cosh(x)/e**2: multiply in this order to avoid inf: + u = r * cosy * HALF_E2; + // r approximates 2sinh(|x|)/e**2: put back the proper sign of x in passing. + v = Math.copySign(r, x) * siny * HALF_E2; + if (Double.isInfinite(u) || Double.isInfinite(v)) { + // A finite x gave rise to an infinite u or v. + throw math.mathRangeError(); + } + + } else { + // Normal case, without risk of overflow. + u = Math.cosh(x) * cosy; + v = Math.sinh(x) * siny; + } + } + + // Compose the result w = u + iv. + w = new PyComplex(u, v); + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(w, z); } /** @@ -391,6 +480,7 @@ /** * Return the sine of z. + * * @param z * @return sin z */ @@ -400,6 +490,7 @@ /** * Return the hyperbolic sine of z. + * * @param z * @return sinh z */ @@ -420,7 +511,7 @@ PyComplex w; if (h) { - // We compute w = sinh(z). Let w = u + iv and z = x + iy. We compute w = sinh(z) from: + // We compute w = sinh(z). Let w = u + iv and z = x + iy. x = z.real; y = z.imag; // Then the function body computes sinh(x+iy), according to: @@ -428,13 +519,11 @@ // v = cosh(x) sin(y), // And we return w = u + iv. } else { - // We compute w = sin(z). Unusually, let z = y - ix. + // We compute w = sin(z). Unusually, let z = y - ix, so x + iy = iz. y = z.real; x = -z.imag; - // Then the function body computes sinh(x+iy) = sinh(iz) = i sin(z), according to: - // u = sinh(x) cos(y), - // v = cosh(x) sin(y). - // But we finally return w = v - iu = sin(z) + // Then the function body computes sinh(x+iy) = sinh(iz) = i sin(z) as before, + // but we finally return w = v - iu = sin(z). } if (y == 0.) { @@ -458,7 +547,7 @@ if (!Double.isNaN(cosy)) { // w = (inf,inf), but "rotated" by the direction cosines. u = x * cosy; - v = Math.abs(x) * siny; + v = absx * siny; } else { // Provisionally w = (inf,nan), which will raise domain error if y!=nan. u = x; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Re-work_cmath=2Esin_and_cma?= =?utf-8?q?th=2Esinh_for_accuracy_and_corner_cases=2E?= Message-ID: <20150120220714.118104.27026@psf.io> https://hg.python.org/jython/rev/6081dd31e6a4 changeset: 7546:6081dd31e6a4 user: Jeff Allen date: Sat Jan 10 17:04:20 2015 +0000 summary: Re-work cmath.sin and cmath.sinh for accuracy and corner cases. files: src/org/python/modules/cmath.java | 118 ++++++++++++++++- 1 files changed, 110 insertions(+), 8 deletions(-) diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -22,6 +22,14 @@ private static final double ROOT_HALF = 0.70710678118654752440; /** ln({@link Double#MAX_VALUE}) or a little less */ private static final double NEARLY_LN_DBL_MAX = 709.4361393; + /** + * For x larger than this, e-x is negligible compared with + * ex, or equivalently 1 is negligible compared with e2x, in + * IEEE-754 floating point. Beyond this, sinh x and cosh x are adequately + * approximated by 0.5ex. The smallest theoretical value is 27 ln(2). + */ + private static final double ATLEAST_27LN2 = 18.72; + private static final double HALF_E2 = 0.5 * Math.E * Math.E; /** log10e (Ref: Abramowitz & Stegun [1972], p3). */ private static final double LOG10E = 0.43429448190325182765; @@ -381,16 +389,110 @@ } } - public static PyComplex sin(PyObject in) { - PyComplex x = complexFromPyObject(in); - return new PyComplex(Math.sin(x.real) * math.cosh(x.imag), Math.cos(x.real) - * math.sinh(x.imag)); + /** + * Return the sine of z. + * @param z + * @return sin z + */ + public static PyComplex sin(PyObject z) { + return sinOrSinh(complexFromPyObject(z), false); } - public static PyComplex sinh(PyObject in) { - PyComplex x = complexFromPyObject(in); - return new PyComplex(Math.cos(x.imag) * math.sinh(x.real), Math.sin(x.imag) - * math.cosh(x.real)); + /** + * Return the hyperbolic sine of z. + * @param z + * @return sinh z + */ + public static PyComplex sinh(PyObject z) { + return sinOrSinh(complexFromPyObject(z), true); + } + + /** + * Helper to compute either sin z or sinh z. + * + * @param z + * @param h true to compute sinh z, false to compute sin + * z. + * @return + */ + private static PyComplex sinOrSinh(PyComplex z, boolean h) { + double x, y, u, v; + PyComplex w; + + if (h) { + // We compute w = sinh(z). Let w = u + iv and z = x + iy. We compute w = sinh(z) from: + x = z.real; + y = z.imag; + // Then the function body computes sinh(x+iy), according to: + // u = sinh(x) cos(y), + // v = cosh(x) sin(y), + // And we return w = u + iv. + } else { + // We compute w = sin(z). Unusually, let z = y - ix. + y = z.real; + x = -z.imag; + // Then the function body computes sinh(x+iy) = sinh(iz) = i sin(z), according to: + // u = sinh(x) cos(y), + // v = cosh(x) sin(y). + // But we finally return w = v - iu = sin(z) + } + + if (y == 0.) { + // Real argument for sinh (or imaginary for sin): use real library. + u = math.sinh(x); // This will raise a range error on overflow. + // v follows the sign of y (which could be -0.0). + v = y; + + } else if (x == 0.) { + // Imaginary argument for sinh (or real for sin): imaginary result at this point. + v = Math.sin(y); + // u follows sign of x (which could be -0.0). + u = x; + + } else { + + // The trig calls will not throw, although if y is infinite, they return nan. + double cosy = Math.cos(y), siny = Math.sin(y), absx = Math.abs(x); + + if (absx == Double.POSITIVE_INFINITY) { + if (!Double.isNaN(cosy)) { + // w = (inf,inf), but "rotated" by the direction cosines. + u = x * cosy; + v = Math.abs(x) * siny; + } else { + // Provisionally w = (inf,nan), which will raise domain error if y!=nan. + u = x; + v = Double.NaN; + } + + } else if (absx > ATLEAST_27LN2) { + // Use 0.5*e**x approximation. This is also the region where we risk overflow. + double r = Math.exp(absx - 2.); + // r approximates 2cosh(x)/e**2: multiply in this order to avoid inf: + v = r * siny * HALF_E2; + // r approximates 2sinh(|x|)/e**2: put back the proper sign of x in passing. + u = Math.copySign(r, x) * cosy * HALF_E2; + if (Double.isInfinite(u) || Double.isInfinite(v)) { + // A finite x gave rise to an infinite u or v. + throw math.mathRangeError(); + } + + } else { + // Normal case, without risk of overflow. + u = Math.sinh(x) * cosy; + v = Math.cosh(x) * siny; + } + } + + // Compose the result w according to whether we're computing sin(z) or sinh(z). + if (h) { + w = new PyComplex(u, v); // w = u + iv = sinh(x+iy). + } else { + w = new PyComplex(v, -u); // w = v - iu = sin(y-ix) = sin(z) + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(w, z); } /** -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Re-work_cmath=2Eacos=2C_aco?= =?utf-8?q?sh=2C_asin_and_asinh_for_accuracy_and_corner_cases=2E?= Message-ID: <20150120220715.103289.46950@psf.io> https://hg.python.org/jython/rev/e267f6b3e6b0 changeset: 7549:e267f6b3e6b0 user: Jeff Allen date: Sat Jan 17 15:00:58 2015 +0000 summary: Re-work cmath.acos, acosh, asin and asinh for accuracy and corner cases. Also, a few notes on how the code (which is taken from CPython) actually works. files: src/org/python/modules/cmath.java | 308 ++++++++++++++--- 1 files changed, 250 insertions(+), 58 deletions(-) diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -34,41 +34,6 @@ /** log10e (Ref: Abramowitz & Stegun [1972], p3). */ private static final double LOG10E = 0.43429448190325182765; - private static PyComplex c_prodi(PyComplex x) { - return (PyComplex)x.__mul__(i); - } - - private static boolean isNaN(PyComplex x) { - return Double.isNaN(x.real) || Double.isNaN(x.imag); - } - - private static double abs(PyComplex x) { - boolean isNaN = isNaN(x); - boolean isInfinite = !isNaN && (Double.isInfinite(x.real) || Double.isInfinite(x.imag)); - if (isNaN) { - return Double.NaN; - } - if (isInfinite) { - return Double.POSITIVE_INFINITY; - } - double real_abs = Math.abs(x.real); - double imag_abs = Math.abs(x.imag); - - if (real_abs < imag_abs) { - if (x.imag == 0.0) { - return real_abs; - } - double q = x.real / x.imag; - return imag_abs * Math.sqrt(1 + q * q); - } else { - if (x.real == 0.0) { - return imag_abs; - } - double q = x.imag / x.real; - return real_abs * Math.sqrt(1 + q * q); - } - } - private static PyComplex complexFromPyObject(PyObject obj) { // If op is already of type PyComplex_Type, return its value if (obj instanceof PyComplex) { @@ -102,34 +67,261 @@ return new PyComplex(obj.asDouble(), 0); } - public static PyObject acos(PyObject in) { - PyComplex x = complexFromPyObject(in); - return c_prodi(log(x.__add__(i.__mul__(sqrt(one.__sub__(x.__mul__(x))))))).__neg__(); + /** + * Return the arc cosine of w. There are two branch cuts. One extends right from 1 along the + * real axis to ∞, continuous from below. The other extends left from -1 along the real + * axis to -∞, continuous from above. + * + * @param w + * @return cos-1w + */ + public static PyComplex acos(PyObject w) { + return _acos(complexFromPyObject(w)); } - public static PyComplex acosh(PyObject in) { - PyComplex x = complexFromPyObject(in); - PyComplex a = sqrt(x.__sub__(one)); - PyComplex b = sqrt(x.__add__(one)); - PyComplex c = sqrt(half); - PyComplex r = log(c.__mul__(b.__add__(a))); - return ((PyComplex)r.__add__(r)); + /** + * Helper to compute cos-1w. The method used is as in CPython: + *

+ * a = (1-w)½ = √2 sin z/2
+ * b = (1+w)½ = √2 cos z/2 + *

+ * Then, with z = x+iy, a = a1+ia2, and b = + * b1+ib2, + *

+ * a1 / b1 = tan x/2
+ * a2b1 - a1b2 = sinh y + *

+ * and we use {@link Math#atan2(double, double)} and {@link math#asinh(double)} to obtain + * x and y. + *

+ * For w sufficiently large that w2≫1, cos-1w + * ≈ -i ln(2w). + * + * @param w + * @return cos-1w + */ + private static PyComplex _acos(PyComplex w) { + + // Let z = x + iy and w = u + iv. + double x, y, u = w.real, v = w.imag; + + if (Math.abs(u) > 0x1p27 || Math.abs(v) > 0x1p27) { + /* + * w is large: approximate 2cos(z) by exp(i(x+iy)) or exp(-i(x+iy)), whichever + * dominates. Hence, z = x+iy = i ln(2(u+iv)) or -i ln(2(u+iv)) + */ + x = Math.atan2(Math.abs(v), u); + y = Math.copySign(logHypot(u, v) + math.LN2, -v); + + } else if (Double.isNaN(v)) { + // Special cases + x = (u == 0.) ? Math.PI / 2. : v; + y = v; + + } else { + // Normal case, without risk of overflow. + PyComplex a = sqrt(new PyComplex(1. - u, -v)); // a = sqrt(1-w) = sqrt(2) sin(z/2) + PyComplex b = sqrt(new PyComplex(1 + u, v)); // b = sqrt(1+w) = sqrt(2) cos(z/2) + // Arguments here are sin(x/2)cosh(y/2), cos(x/2)cosh(y/2) giving tan(x/2) + x = 2. * Math.atan2(a.real, b.real); + // 2 (cos(x/2)**2+sin(x/2)**2) sinh(y/2)cosh(y/2) = sinh y + y = math.asinh(a.imag * b.real - a.real * b.imag); + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(new PyComplex(x, y), w); } - public static PyComplex asin(PyObject in) { - PyComplex x = complexFromPyObject(in); - PyComplex squared = (PyComplex)x.__mul__(x); - PyComplex sq1_minus_xsq = sqrt(one.__sub__(squared)); - return (PyComplex)c_prodi(log(sq1_minus_xsq.__add__(c_prodi(x)))).__neg__(); + /** + * Return the hyperbolic arc cosine of w. There is one branch cut, extending left from 1 along + * the real axis to -∞, continuous from above. + * + * @param w + * @return cosh-1w + */ + public static PyComplex acosh(PyObject w) { + return _acosh(complexFromPyObject(w)); } - public static PyComplex asinh(PyObject in) { - PyComplex x = complexFromPyObject(in); - PyComplex a = sqrt(x.__add__(i)); - PyComplex b = sqrt(x.__sub__(i)); - PyComplex z = sqrt(half); - PyComplex r = log(z.__mul__(a.__add__(b))); - return ((PyComplex)r.__add__(r)); + /** + * Helper to compute z = cosh-1w. The method used is as in CPython: + *

+ * a = (w-1)½ = √2 sinh z/2
+ * b = (w+1)½ = √2 cosh z/2 + *

+ * Then, with z = x+iy, a = a1+ia2, and b = + * b1+ib2, + *

+ * a1b1 + a2b2 = sinh x
+ * a2 / b1 = tan y/2 + *

+ * and we use {@link math#asinh(double)} and {@link Math#atan2(double, double)} to obtain + * x and y. + *

+ * For w sufficiently large that w2≫1, + * cosh-1w ≈ ln(2w). We do not use this method also to compute + * cos-1w, because the branch cuts do not correspond. + * + * @param w + * @return cosh-1w + */ + private static PyComplex _acosh(PyComplex w) { + + // Let z = x + iy and w = u + iv. + double x, y, u = w.real, v = w.imag; + + if (Math.abs(u) > 0x1p27 || Math.abs(v) > 0x1p27) { + /* + * w is large: approximate 2cosh(z) by exp(x+iy) or exp(-x-iy), whichever dominates. + * Hence, z = x+iy = ln(2(u+iv)) or -ln(2(u+iv)) + */ + x = logHypot(u, v) + math.LN2; + y = Math.atan2(v, u); + + } else if (v == 0. && !Double.isNaN(u)) { + /* + * We're on the real axis (and maybe the branch cut). u = cosh x cos y. In all cases, + * the sign of y follows v. + */ + if (u >= 1.) { + // As real library, cos y = 1, u = cosh x. + x = math.acosh(u); + y = v; + } else if (u < -1.) { + // Left part of cut: cos y = -1, u = -cosh x + x = math.acosh(-u); + y = Math.copySign(Math.PI, v); + } else { + // -1 <= u <= 1: cosh x = 1, u = cos y. + x = 0.; + y = Math.copySign(Math.acos(u), v); + } + + } else { + // Normal case, without risk of overflow. + PyComplex a = sqrt(new PyComplex(u - 1., v)); // a = sqrt(w-1) = sqrt(2) sinh(z/2) + PyComplex b = sqrt(new PyComplex(u + 1., v)); // b = sqrt(w+1) = sqrt(2) cosh(z/2) + // 2 sinh(x/2)cosh(x/2) (cos(y/2)**2+sin(y/2)**2) = sinh x + x = math.asinh(a.real * b.real + a.imag * b.imag); + // Arguments here are cosh(x/2)sin(y/2) and cosh(x/2)cos(y/2) giving tan y/2 + y = 2. * Math.atan2(a.imag, b.real); + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(new PyComplex(x, y), w); + } + + /** + * Return the arc sine of w. There are two branch cuts. One extends right from 1 along the real + * axis to ∞, continuous from below. The other extends left from -1 along the real axis to + * -∞, continuous from above. + * + * @param w + * @return sin-1w + */ + public static PyComplex asin(PyObject w) { + return asinOrAsinh(complexFromPyObject(w), false); + } + + /** + * Return the hyperbolic arc sine of w. There are two branch cuts. One extends from 1j along the + * imaginary axis to ∞j, continuous from the right. The other extends from -1j along the + * imaginary axis to -∞j, continuous from the left. + * + * @param w + * @return sinh-1w + */ + public static PyComplex asinh(PyObject w) { + return asinOrAsinh(complexFromPyObject(w), true); + } + + /** + * Helper to compute either sin-1w or sinh-1w. The method + * used is as in CPython: + *

+ * a = (1-iw)½ = √2 sin(π/4-iz/2)
+ * b = (1+iw)½ = √2 cos(π/4-iz/2) + *

+ * Then, with w = u+iv, z = x+iy, a = a1+ia2, and + * b = b1+ib2, + *

+ * a1b2 - a2b2 = sinh x
+ * v / (a2b1 - a1b2) = tan y + *

+ * and we use {@link math#asinh(double)} and {@link Math#atan2(double, double)} to obtain + * x and y. + *

+ * For w sufficiently large that w2≫1, + * sinh-1w ≈ ln(2w). When computing sin-1w, we + * evaluate -i sinh-1iw instead. + * + * @param w + * @param h true to compute sinh-1w, false to + * compute sin-1w. + * @return sinh-1w or sin-1w + */ + private static PyComplex asinOrAsinh(PyComplex w, boolean h) { + double u, v, x, y; + PyComplex z; + + if (h) { + // We compute z = asinh(w). Let z = x + iy and w = u + iv. + u = w.real; + v = w.imag; + // Then the function body computes x + iy = asinh(w). + } else { + // We compute w = asin(z). Unusually, let w = u - iv, so u + iv = iw. + v = w.real; + u = -w.imag; + // Then as before, the function body computes asinh(u+iv) = asinh(iw) = i asin(w), + // but we finally return z = y - ix = -i asinh(iw) = asin(w). + } + + if (Double.isNaN(u)) { + // Special case for nan in real part. Default clause deals naturally with v=nan. + if (v == 0.) { + x = u; + y = v; + } else if (Double.isInfinite(v)) { + x = Double.POSITIVE_INFINITY; + y = u; + } else { // Any other value of v -> nan+nanj + x = y = u; + } + + } else if (Math.abs(u) > 0x1p27 || Math.abs(v) > 0x1p27) { + /* + * w is large: approximate 2sinh(z) by exp(x+iy) or -exp(-x-iy), whichever dominates. + * Hence, z = x+iy = ln(2(u+iv)) or -ln(-2(u+iv)) + */ + x = logHypot(u, v) + math.LN2; + if (Math.copySign(1., u) > 0.) { + y = Math.atan2(v, u); + } else { + // Adjust for sign, choosing the angle so that -pi/2 < y < pi/2 + x = -x; + y = Math.atan2(v, -u); + } + + } else { + // Normal case, without risk of overflow. + PyComplex a = sqrt(new PyComplex(1. + v, -u)); // a = sqrt(1-iw) + PyComplex b = sqrt(new PyComplex(1. - v, u)); // b = sqrt(1+iw) + // Combine the parts so as that terms in y cancel, leaving us with sinh x: + x = math.asinh(a.real * b.imag - a.imag * b.real); + // The arguments are v = cosh x sin y, and cosh x cos y + y = Math.atan2(v, a.real * b.real - a.imag * b.imag); + } + + // Compose the result w according to whether we're computing asin(w) or asinh(w). + if (h) { + z = new PyComplex(x, y); // z = x + iy = asinh(u+iv). + } else { + z = new PyComplex(y, -x); // z = y - ix = -i asinh(v-iu) = sin(w) + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(z, w); } public static PyComplex atan(PyObject in) { @@ -522,7 +714,7 @@ // We compute w = sin(z). Unusually, let z = y - ix, so x + iy = iz. y = z.real; x = -z.imag; - // Then the function body computes sinh(x+iy) = sinh(iz) = i sin(z) as before, + // Then as before, the function body computes sinh(x+iy) = sinh(iz) = i sin(z), // but we finally return w = v - iu = sin(z). } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:17 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:17 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Re-work_cmath=2Eatan=2C_and?= =?utf-8?q?_atanh_for_accuracy_and_corner_cases=2E?= Message-ID: <20150120220715.103297.22093@psf.io> https://hg.python.org/jython/rev/c126535fc9f0 changeset: 7550:c126535fc9f0 user: Jeff Allen date: Sun Jan 18 22:25:03 2015 +0000 summary: Re-work cmath.atan, and atanh for accuracy and corner cases. Close to the CPython implementation, but a few more special cases. files: src/org/python/modules/cmath.java | 141 ++++++++++++++++- 1 files changed, 129 insertions(+), 12 deletions(-) diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -13,11 +13,6 @@ public static final PyFloat pi = new PyFloat(Math.PI); public static final PyFloat e = new PyFloat(Math.E); - private static final PyComplex one = new PyComplex(1.0, 0.0); - private static final PyComplex half = new PyComplex(0.5, 0.0); - private static final PyComplex i = new PyComplex(0.0, 1.0); - private static final PyComplex half_i = new PyComplex(0.0, 0.5); - /** 2 (Ref: Abramowitz & Stegun [1972], p2). */ private static final double ROOT_HALF = 0.70710678118654752440; /** ln({@link Double#MAX_VALUE}) or a little less */ @@ -317,21 +312,143 @@ if (h) { z = new PyComplex(x, y); // z = x + iy = asinh(u+iv). } else { - z = new PyComplex(y, -x); // z = y - ix = -i asinh(v-iu) = sin(w) + z = new PyComplex(y, -x); // z = y - ix = -i asinh(v-iu) = asin(w) } // If that generated a nan, and there wasn't one in the argument, raise a domain error. return exceptNaN(z, w); } - public static PyComplex atan(PyObject in) { - PyComplex x = complexFromPyObject(in); - return (PyComplex)half_i.__mul__(log(i.__add__(x).__div__(i.__sub__(x)))); + /** + * Return the arc tangent of w. There are two branch cuts. One extends from 1j along the + * imaginary axis to ∞j, continuous from the right. The other extends from -1j along the + * imaginary axis to -∞j, continuous from the left. + * + * @param w + * @return tan-1w + */ + public static PyComplex atan(PyObject w) { + return atanOrAtanh(complexFromPyObject(w), false); } - public static PyComplex atanh(PyObject in) { - PyComplex x = complexFromPyObject(in); - return (PyComplex)half.__mul__(log(one.__add__(x).__div__(one.__sub__(x)))); + /** + * Return the hyperbolic arc tangent of w. There are two branch cuts. One extends from 1 along + * the real axis to ∞, continuous from below. The other extends from -1 along the real + * axis to -∞, continuous from above. + * + * @param w + * @return tanh-1w + */ + public static PyComplex atanh(PyObject w) { + return atanOrAtanh(complexFromPyObject(w), true); + } + + /** + * Helper to compute either tan-1w or tanh-1w. The method + * used is close to that used in CPython. For z = tanh-1w: + *

+ * z = ½ln(1 + 2w/(1-w)) + *

+ * Then, letting z = x+iy, and w = u+iv, + *

+ * x = ¼ln(1 + 4u/((1-u)2+v2)) = + * -¼ln(1 - 4u/((1+u)2+v2))
+ * y = ½tan-1(2v / ((1+u)(1-u)-v2))
+ *

+ * We use {@link math#log1p(double)} and {@link Math#atan2(double, double)} to obtain x + * and y. The second expression for x is used when u<0. For + * w sufficiently large that w2≫1, tanh-1w + * ≈ 1/w ± iπ/2). For small w, tanh-1w ≈ + * w. When computing tan-1w, we evaluate -i + * tanh-1iw instead. + * + * @param w + * @param h true to compute tanh-1w, false to + * compute tan-1w. + * @return tanh-1w or tan-1w + */ + private static PyComplex atanOrAtanh(PyComplex w, boolean h) { + double u, v, x, y; + PyComplex z; + + if (h) { + // We compute z = atanh(w). Let z = x + iy and w = u + iv. + u = w.real; + v = w.imag; + // Then the function body computes x + iy = atanh(w). + } else { + // We compute w = atan(z). Unusually, let w = u - iv, so u + iv = iw. + v = w.real; + u = -w.imag; + // Then as before, the function body computes atanh(u+iv) = atanh(iw) = i atan(w), + // but we finally return z = y - ix = -i atanh(iw) = atan(w). + } + + double absu = Math.abs(u), absv = Math.abs(v); + + if (absu >= 0x1p511 || absv >= 0x1p511) { + // w is large: approximate atanh(w) by 1/w + i pi/2. 1/w = conjg(w)/|w|**2. + if (Double.isInfinite(absu) || Double.isInfinite(absv)) { + x = Math.copySign(0., u); + } else { + // w is also too big to square, carry a 2**-N scaling factor. + int N = 520; + double uu = Math.scalb(u, -N), vv = Math.scalb(v, -N); + double mod2w = uu * uu + vv * vv; + x = Math.scalb(uu / mod2w, -N); + } + // We don't need the imaginary part of 1/z. Just pi/2 with the sign of v. (If not nan.) + if (Double.isNaN(v)) { + y = v; + } else { + y = Math.copySign(Math.PI / 2., v); + } + + } else if (absu < 0x1p-53) { + // u is small enough that u**2 may be neglected relative to 1. + if (absv > 0x1p-27) { + // v is not small, but is not near overflow either. + double v2 = v * v; + double d = 1. + v2; + x = Math.copySign(Math.log1p(4. * absu / d), u) * 0.25; + y = Math.atan2(2. * v, 1. - v2) * 0.5; + } else { + // v is also small enough that v**2 may be neglected (or is nan). So z = w. + x = u; + y = v; + } + + } else if (absu == 1. && absv < 0x1p-27) { + // w is close to +1 or -1: needs a different expression, good as v->0 + x = Math.copySign(Math.log(absv) - math.LN2, u) * 0.5; + if (v == 0.) { + y = Double.NaN; + } else { + y = Math.copySign(Math.atan2(2., absv), v) * 0.5; + } + + } else { + /* + * Normal case, without risk of overflow. The basic expression is z = + * 0.5*ln((1+w)/(1-w)), which for positive u we rearrange as 0.5*ln(1+2w/(1-w)) and for + * negative u as -0.5*ln(1-2w/(1+w)). By use of absu, we reduce the difference between + * the expressions fo u>=0 and u<0 to a sign transfer. + */ + double lmu = (1. - absu), lpu = (1. + absu), v2 = v * v; + double d = lmu * lmu + v2; + x = Math.copySign(Math.log1p(4. * absu / d), u) * 0.25; + y = Math.atan2(2. * v, lmu * lpu - v2) * 0.5; + } + + // Compose the result w according to whether we're computing atan(w) or atanh(w). + if (h) { + z = new PyComplex(x, y); // z = x + iy = atanh(u+iv). + } else { + z = new PyComplex(y, -x); // z = y - ix = -i atanh(v-iu) = atan(w) + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(z, w); } /** -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:17 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:17 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Rectify_cmath=2Erect=28=29_?= =?utf-8?q?corner-cases=2E?= Message-ID: <20150120220715.69918.99243@psf.io> https://hg.python.org/jython/rev/53f2008ed99f changeset: 7551:53f2008ed99f user: Jeff Allen date: Sun Jan 18 23:43:35 2015 +0000 summary: Rectify cmath.rect() corner-cases. files: src/org/python/modules/cmath.java | 58 +++++++++++++----- 1 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -625,25 +625,42 @@ return new PyTuple(new PyFloat(r), new PyFloat(phi)); } + /** + * Return the complex number x with polar coordinates r and phi. Equivalent to + * r * (math.cos(phi) + math.sin(phi)*1j). + * + * @param r radius + * @param phi angle + * @return + */ public static PyComplex rect(double r, double phi) { - // Handle various edge cases + double x, y; + if (Double.isInfinite(r) && (Double.isInfinite(phi) || Double.isNaN(phi))) { - return new PyComplex(Double.POSITIVE_INFINITY, Double.NaN); + x = Double.POSITIVE_INFINITY; + y = Double.NaN; + + } else if (phi == 0.0) { + // cos(phi)=1, sin(phi)=phi: finesse oddball r in computing y, but not x. + x = r; + if (Double.isNaN(r)) { + y = phi; + } else if (Double.isInfinite(r)) { + y = phi * Math.copySign(1., r); + } else { + y = phi * r; + } + + } else if (r == 0.0 && (Double.isInfinite(phi) || Double.isNaN(phi))) { + // Ignore any problems (inf, nan) with phi + x = y = 0.; + + } else { + // Text-book case, using the trig functions. + x = r * Math.cos(phi); + y = r * Math.sin(phi); } - if (phi == 0.0) { // NB this test will succeed if phi is 0.0 or -0.0 - if (Double.isNaN(r)) { - return new PyComplex(Double.NaN, 0.0); - } else if (r == Double.POSITIVE_INFINITY) { - return new PyComplex(r, phi); - } else if (r == Double.NEGATIVE_INFINITY) { - return new PyComplex(r, -phi); - } - } - if (r == 0.0 && (Double.isInfinite(phi) || Double.isNaN(phi))) { - return new PyComplex(0.0, 0.0); - } - - return new PyComplex(r * Math.cos(phi), r * Math.sin(phi)); + return exceptNaN(new PyComplex(x, y), r, phi); } /** @@ -1128,6 +1145,15 @@ } } + private static PyComplex exceptNaN(PyComplex result, double a, double b) throws PyException { + if ((Double.isNaN(result.real) || Double.isNaN(result.imag)) + && !(Double.isNaN(a) || Double.isNaN(b))) { + throw math.mathDomainError(); + } else { + return result; + } + } + /** * Turn an infinite result into a thrown OverflowError, a math range error, if the * original argument was not itself infinite. A PyComplex is infinite if either -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:17 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:17 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_test=2Emath=5Fcmath_?= =?utf-8?q?to_count/log_the_discrepancies?= Message-ID: <20150120220715.93191.69495@psf.io> https://hg.python.org/jython/rev/e89bf3a7c8dd changeset: 7552:e89bf3a7c8dd user: Jeff Allen date: Tue Jan 20 19:17:32 2015 +0000 summary: Update test.math_cmath to count/log the discrepancies test_cmath is skip-free. The case test_cmath_matches_math tests more functions, and test_specific_values no longer exits at the first failure, but counts them. Error detail useful to cmath development is reported in verbose mode. files: Lib/test/test_cmath.py | 144 ++++++++++-------- NEWS | 2 + src/org/python/modules/cmath.java | 25 +-- 3 files changed, 87 insertions(+), 84 deletions(-) diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -1,4 +1,4 @@ -from test.test_support import run_unittest, is_jython +from test.test_support import run_unittest, verbose from test.test_math import parse_testfile, test_file import unittest import cmath, math @@ -52,7 +52,6 @@ 'cos', 'cosh', 'exp', 'log', 'log10', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']] # test first and second arguments independently for 2-argument log - test_functions.append(lambda x : cmath.log(x, 1729. + 0j)) test_functions.append(lambda x : cmath.log(14.-27j, x)) @@ -244,24 +243,30 @@ unit_interval = test_values + [-x for x in test_values] + \ [0., 1., -1.] + # test_values for acosh, atanh + ge_one = [1.] + [1./x for x in test_values] + unit_open = test_values + [-x for x in test_values] + [0.] + # test_values for log, log10, sqrt - positive = test_values + [1.] + [1./x for x in test_values] + positive = test_values + ge_one nonnegative = [0.] + positive # test_values for functions defined on the whole real line real_line = [0.] + positive + [-x for x in positive] test_functions = { - # FIXME uncomment tests for Jython - #'acos' : unit_interval, - #'asin' : unit_interval, - #'atan' : real_line, - #'cos' : real_line, - #'cosh' : real_line, + 'acos' : unit_interval, + 'asin' : unit_interval, + 'atan' : real_line, + 'acosh' : ge_one, # Jython added + 'asinh' : real_line, # Jython added + 'atanh' : unit_open, # Jython added + 'cos' : real_line, + 'cosh' : real_line, 'exp' : real_line, 'log' : positive, 'log10' : positive, - #'sin' : real_line, + 'sin' : real_line, 'sinh' : real_line, 'sqrt' : nonnegative, 'tan' : real_line, @@ -273,7 +278,7 @@ for v in values: z = complex_fn(v) self.rAssertAlmostEqual(float_fn(v), z.real) - self.rAssertAlmostEqual(0., z.imag) + self.assertEqual(0., z.imag) # test two-argument version of log with various bases for base in [0.5, 2., 10.]: @@ -282,10 +287,9 @@ self.rAssertAlmostEqual(math.log(v, base), z.real) self.assertEqual(0., z.imag) - @unittest.skipIf(is_jython, "FIXME: not working in Jython") def test_specific_values(self): if not float.__getformat__("double").startswith("IEEE"): - return + self.skipTest('needs IEEE double') def rect_complex(z): """Wrapped version of rect that accepts a complex number instead of @@ -297,78 +301,88 @@ two floats.""" return complex(*polar(z)) + raised_fmt = '\n' \ + '{}: {}(complex({!r}, {!r}))\n' \ + 'Raised: {!r}\n' \ + 'Expected: complex({!r}, {!r})' + not_raised_fmt = '\n' \ + '{} not raised in test {}: {}(complex({!r}, {!r}))\n' \ + 'Received: complex({!r}, {!r})' + value_fmt = '\n' \ + '{}: {}(complex({!r}, {!r}))\n' \ + 'Expected: complex({!r}, {!r})\n' \ + 'Received: complex({!r}, {!r})\n' \ + 'Received value insufficiently close to expected value.' + failures = 0 + for id, fn, ar, ai, er, ei, flags in parse_testfile(test_file): arg = complex(ar, ai) - expected = complex(er, ei) if fn == 'rect': function = rect_complex elif fn == 'polar': function = polar_complex else: function = getattr(cmath, fn) - if 'divide-by-zero' in flags or 'invalid' in flags: - try: + + try: + # Catch and count failing test cases locally + if 'divide-by-zero' in flags or 'invalid' in flags: try: actual = function(arg) except ValueError: - continue + pass else: - self.fail('ValueError not raised in test ' - '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai)) - except AssertionError, ex: - print "Got", function, ex - except BaseException, ex: - print "Got", function, ex + failures += 1 + self.fail(not_raised_fmt.format('ValueError', + id, fn, ar, ai, actual.real, actual.imag)) - try: - if 'overflow' in flags: + elif 'overflow' in flags: try: actual = function(arg) except OverflowError: - continue - except BaseException, ex: - print "\nGot", function, ex + pass else: - self.fail('OverflowError not raised in test ' - '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai)) - except AssertionError, ex: - print "\nGot", function, ex + failures += 1 + self.fail(not_raised_fmt.format('OverflowError', + id, fn, ar, ai, actual.real, actual.imag)) - try: - actual = function(arg) - except BaseException, ex: - print "\nGot", function, ex + else : + actual = function(arg) - if 'ignore-real-sign' in flags: - actual = complex(abs(actual.real), actual.imag) - expected = complex(abs(expected.real), expected.imag) - if 'ignore-imag-sign' in flags: - actual = complex(actual.real, abs(actual.imag)) - expected = complex(expected.real, abs(expected.imag)) + # Make sign of expected conform to actual, where ignored. + exr, exi = er, ei + if 'ignore-real-sign' in flags: + exr = math.copysign(er, actual.real) + if 'ignore-imag-sign' in flags: + exi = math.copysign(ei, actual.imag) - # for the real part of the log function, we allow an - # absolute error of up to 2e-15. - if fn in ('log', 'log10'): - real_abs_err = 2e-15 - else: - real_abs_err = 5e-323 + # for the real part of the log function, we allow an + # absolute error of up to 2e-15. + if fn in ('log', 'log10'): + real_abs_err = 2e-15 + else: + real_abs_err = 5e-323 - error_message = ( - '{}: {}(complex({!r}, {!r}))\n' - 'Expected: complex({!r}, {!r})\n' - 'Received: complex({!r}, {!r})\n' - 'Received value insufficiently close to expected value.' - ).format(id, fn, ar, ai, - expected.real, expected.imag, - actual.real, actual.imag) - try: - self.rAssertAlmostEqual(expected.real, actual.real, - abs_err=real_abs_err, - msg=error_message) - self.rAssertAlmostEqual(expected.imag, actual.imag, - msg=error_message) - except AssertionError, ex: - print "\nGot", ex, error_message + error_message = value_fmt.format(id, fn, ar, ai, er, ei, + actual.real, actual.imag) + self.rAssertAlmostEqual(exr, actual.real, + abs_err=real_abs_err, + msg=error_message) + self.rAssertAlmostEqual(exi, actual.imag, + msg=error_message) + + except AssertionError as ex: + failures += 1 + if verbose : + print(ex) + except BaseException as ex: + failures += 1 + if verbose : + print(raised_fmt.format(id, fn, ar, ai, ex, er, ei)) + + if failures : + self.fail('{} discrepancies'.format(failures)) + def assertCISEqual(self, a, b): eps = 1E-7 @@ -446,6 +460,8 @@ self.assertTrue(math.isnan(abs(complex(2.3, NAN)))) self.assertEqual(abs(complex(INF, NAN)), INF) self.assertTrue(math.isnan(abs(complex(NAN, NAN)))) + + # result overflows if float.__getformat__("double").startswith("IEEE"): self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308)) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ Jython 2.7b4 Bugs Fixed - [ 2037 ] Byte-string containing elements greater than 255 + - [ 2244 ] Weak testing of real math module + - [ 2237 ] Test failures with float and complex Jython 2.7b3 Bugs Fixed diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -1145,6 +1145,11 @@ } } + /** + * Raise ValueError if result is a NaN, but neither + * a nor b is NaN. Same as + * {@link #exceptNaN(PyComplex, PyComplex)}. + */ private static PyComplex exceptNaN(PyComplex result, double a, double b) throws PyException { if ((Double.isNaN(result.real) || Double.isNaN(result.imag)) && !(Double.isNaN(a) || Double.isNaN(b))) { @@ -1154,24 +1159,4 @@ } } - /** - * Turn an infinite result into a thrown OverflowError, a math range error, if the - * original argument was not itself infinite. A PyComplex is infinite if either - * component is infinite. - * - * @param result to return (if we return) - * @param arg to include in check - * @return result if arg was infinite or result was not infinite - * @throws PyException (ValueError) if result was infinite and arg was - * not infinite - */ - private static PyComplex exceptInf(PyComplex result, PyComplex arg) { - if ((Double.isInfinite(result.real) || Double.isInfinite(result.imag)) - && !(Double.isInfinite(arg.real) || Double.isInfinite(arg.imag))) { - throw math.mathRangeError(); - } else { - return result; - } - } - } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Jan 20 23:07:17 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Jan 2015 22:07:17 +0000 Subject: [Jython-checkins] =?utf-8?q?jython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_cmath_changes_to_trunk?= Message-ID: <20150120220716.104138.4387@psf.io> https://hg.python.org/jython/rev/9c81bac53d7a changeset: 7553:9c81bac53d7a parent: 7542:88209128cde8 parent: 7552:e89bf3a7c8dd user: Jeff Allen date: Tue Jan 20 22:06:52 2015 +0000 summary: Merge cmath changes to trunk files: Lib/test/cmath_testcases.txt | 30 +- Lib/test/test_cmath.py | 144 +- Lib/test/test_float_jy.py | 7 + Misc/make_cmath_testcases.py | 14 +- NEWS | 3 +- src/org/python/core/PyFloat.java | 5 +- src/org/python/modules/cmath.java | 1079 ++++++++++++++-- src/org/python/modules/math.java | 8 +- 8 files changed, 1042 insertions(+), 248 deletions(-) diff --git a/Lib/test/cmath_testcases.txt b/Lib/test/cmath_testcases.txt --- a/Lib/test/cmath_testcases.txt +++ b/Lib/test/cmath_testcases.txt @@ -1750,15 +1750,15 @@ cosh0053 cosh 0.0003 0.0 -> 1.0000000450000003375 0.0 cosh0054 cosh 0.2 0.0 -> 1.0200667556190758485 0.0 cosh0055 cosh 1.0 0.0 -> 1.5430806348152437785 0.0 -cosh0056 cosh -1e-18 0.0 -> 1.0 0.0 -cosh0057 cosh -0.0003 0.0 -> 1.0000000450000003375 0.0 -cosh0058 cosh -1.0 0.0 -> 1.5430806348152437785 0.0 +cosh0056 cosh -1e-18 0.0 -> 1.0 -0.0 +cosh0057 cosh -0.0003 0.0 -> 1.0000000450000003375 -0.0 +cosh0058 cosh -1.0 0.0 -> 1.5430806348152437785 -0.0 cosh0059 cosh 1.3169578969248168 0.0 -> 2.0000000000000001504 0.0 -cosh0060 cosh -1.3169578969248168 0.0 -> 2.0000000000000001504 0.0 +cosh0060 cosh -1.3169578969248168 0.0 -> 2.0000000000000001504 -0.0 cosh0061 cosh 17.328679513998633 0.0 -> 16777216.000000021938 0.0 cosh0062 cosh 18.714973875118524 0.0 -> 67108864.000000043662 0.0 cosh0063 cosh 709.7827 0.0 -> 8.9883497833190073272e+307 0.0 -cosh0064 cosh -709.7827 0.0 -> 8.9883497833190073272e+307 0.0 +cosh0064 cosh -709.7827 0.0 -> 8.9883497833190073272e+307 -0.0 -- special values cosh1000 cosh 0.0 0.0 -> 1.0 0.0 @@ -2071,20 +2071,20 @@ cos0023 cos 0.45124351152540226 1.6992693993812158 -> 2.543477948972237 -1.1528193694875477 -- Additional real values (Jython) -cos0050 cos 1e-150 0.0 -> 1.0 0.0 -cos0051 cos 1e-18 0.0 -> 1.0 0.0 -cos0052 cos 1e-09 0.0 -> 0.9999999999999999995 0.0 -cos0053 cos 0.0003 0.0 -> 0.9999999550000003375 0.0 -cos0054 cos 0.2 0.0 -> 0.98006657784124162892 0.0 -cos0055 cos 1.0 0.0 -> 0.5403023058681397174 0.0 +cos0050 cos 1e-150 0.0 -> 1.0 -0.0 +cos0051 cos 1e-18 0.0 -> 1.0 -0.0 +cos0052 cos 1e-09 0.0 -> 0.9999999999999999995 -0.0 +cos0053 cos 0.0003 0.0 -> 0.9999999550000003375 -0.0 +cos0054 cos 0.2 0.0 -> 0.98006657784124162892 -0.0 +cos0055 cos 1.0 0.0 -> 0.5403023058681397174 -0.0 cos0056 cos -1e-18 0.0 -> 1.0 0.0 cos0057 cos -0.0003 0.0 -> 0.9999999550000003375 0.0 cos0058 cos -1.0 0.0 -> 0.5403023058681397174 0.0 -cos0059 cos 1.0471975511965976 0.0 -> 0.50000000000000009945 0.0 -cos0060 cos 2.5707963267948966 0.0 -> -0.84147098480789647357 0.0 +cos0059 cos 1.0471975511965976 0.0 -> 0.50000000000000009945 -0.0 +cos0060 cos 2.5707963267948966 0.0 -> -0.84147098480789647357 -0.0 cos0061 cos -2.5707963267948966 0.0 -> -0.84147098480789647357 0.0 -cos0062 cos 18 0.0 -> 0.66031670824408014482 0.0 -cos0063 cos 18.0 0.0 -> 0.66031670824408014482 0.0 +cos0062 cos 18 0.0 -> 0.66031670824408014482 -0.0 +cos0063 cos 18.0 0.0 -> 0.66031670824408014482 -0.0 -- special values cos1000 cos -0.0 0.0 -> 1.0 0.0 diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -1,4 +1,4 @@ -from test.test_support import run_unittest, is_jython +from test.test_support import run_unittest, verbose from test.test_math import parse_testfile, test_file import unittest import cmath, math @@ -52,7 +52,6 @@ 'cos', 'cosh', 'exp', 'log', 'log10', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']] # test first and second arguments independently for 2-argument log - test_functions.append(lambda x : cmath.log(x, 1729. + 0j)) test_functions.append(lambda x : cmath.log(14.-27j, x)) @@ -244,24 +243,30 @@ unit_interval = test_values + [-x for x in test_values] + \ [0., 1., -1.] + # test_values for acosh, atanh + ge_one = [1.] + [1./x for x in test_values] + unit_open = test_values + [-x for x in test_values] + [0.] + # test_values for log, log10, sqrt - positive = test_values + [1.] + [1./x for x in test_values] + positive = test_values + ge_one nonnegative = [0.] + positive # test_values for functions defined on the whole real line real_line = [0.] + positive + [-x for x in positive] test_functions = { - # FIXME uncomment tests for Jython - #'acos' : unit_interval, - #'asin' : unit_interval, - #'atan' : real_line, - #'cos' : real_line, - #'cosh' : real_line, + 'acos' : unit_interval, + 'asin' : unit_interval, + 'atan' : real_line, + 'acosh' : ge_one, # Jython added + 'asinh' : real_line, # Jython added + 'atanh' : unit_open, # Jython added + 'cos' : real_line, + 'cosh' : real_line, 'exp' : real_line, 'log' : positive, 'log10' : positive, - #'sin' : real_line, + 'sin' : real_line, 'sinh' : real_line, 'sqrt' : nonnegative, 'tan' : real_line, @@ -273,7 +278,7 @@ for v in values: z = complex_fn(v) self.rAssertAlmostEqual(float_fn(v), z.real) - self.rAssertAlmostEqual(0., z.imag) + self.assertEqual(0., z.imag) # test two-argument version of log with various bases for base in [0.5, 2., 10.]: @@ -282,10 +287,9 @@ self.rAssertAlmostEqual(math.log(v, base), z.real) self.assertEqual(0., z.imag) - @unittest.skipIf(is_jython, "FIXME: not working in Jython") def test_specific_values(self): if not float.__getformat__("double").startswith("IEEE"): - return + self.skipTest('needs IEEE double') def rect_complex(z): """Wrapped version of rect that accepts a complex number instead of @@ -297,78 +301,88 @@ two floats.""" return complex(*polar(z)) + raised_fmt = '\n' \ + '{}: {}(complex({!r}, {!r}))\n' \ + 'Raised: {!r}\n' \ + 'Expected: complex({!r}, {!r})' + not_raised_fmt = '\n' \ + '{} not raised in test {}: {}(complex({!r}, {!r}))\n' \ + 'Received: complex({!r}, {!r})' + value_fmt = '\n' \ + '{}: {}(complex({!r}, {!r}))\n' \ + 'Expected: complex({!r}, {!r})\n' \ + 'Received: complex({!r}, {!r})\n' \ + 'Received value insufficiently close to expected value.' + failures = 0 + for id, fn, ar, ai, er, ei, flags in parse_testfile(test_file): arg = complex(ar, ai) - expected = complex(er, ei) if fn == 'rect': function = rect_complex elif fn == 'polar': function = polar_complex else: function = getattr(cmath, fn) - if 'divide-by-zero' in flags or 'invalid' in flags: - try: + + try: + # Catch and count failing test cases locally + if 'divide-by-zero' in flags or 'invalid' in flags: try: actual = function(arg) except ValueError: - continue + pass else: - self.fail('ValueError not raised in test ' - '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai)) - except AssertionError, ex: - print "Got", function, ex - except BaseException, ex: - print "Got", function, ex + failures += 1 + self.fail(not_raised_fmt.format('ValueError', + id, fn, ar, ai, actual.real, actual.imag)) - try: - if 'overflow' in flags: + elif 'overflow' in flags: try: actual = function(arg) except OverflowError: - continue - except BaseException, ex: - print "\nGot", function, ex + pass else: - self.fail('OverflowError not raised in test ' - '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai)) - except AssertionError, ex: - print "\nGot", function, ex + failures += 1 + self.fail(not_raised_fmt.format('OverflowError', + id, fn, ar, ai, actual.real, actual.imag)) - try: - actual = function(arg) - except BaseException, ex: - print "\nGot", function, ex + else : + actual = function(arg) - if 'ignore-real-sign' in flags: - actual = complex(abs(actual.real), actual.imag) - expected = complex(abs(expected.real), expected.imag) - if 'ignore-imag-sign' in flags: - actual = complex(actual.real, abs(actual.imag)) - expected = complex(expected.real, abs(expected.imag)) + # Make sign of expected conform to actual, where ignored. + exr, exi = er, ei + if 'ignore-real-sign' in flags: + exr = math.copysign(er, actual.real) + if 'ignore-imag-sign' in flags: + exi = math.copysign(ei, actual.imag) - # for the real part of the log function, we allow an - # absolute error of up to 2e-15. - if fn in ('log', 'log10'): - real_abs_err = 2e-15 - else: - real_abs_err = 5e-323 + # for the real part of the log function, we allow an + # absolute error of up to 2e-15. + if fn in ('log', 'log10'): + real_abs_err = 2e-15 + else: + real_abs_err = 5e-323 - error_message = ( - '{}: {}(complex({!r}, {!r}))\n' - 'Expected: complex({!r}, {!r})\n' - 'Received: complex({!r}, {!r})\n' - 'Received value insufficiently close to expected value.' - ).format(id, fn, ar, ai, - expected.real, expected.imag, - actual.real, actual.imag) - try: - self.rAssertAlmostEqual(expected.real, actual.real, - abs_err=real_abs_err, - msg=error_message) - self.rAssertAlmostEqual(expected.imag, actual.imag, - msg=error_message) - except AssertionError, ex: - print "\nGot", ex, error_message + error_message = value_fmt.format(id, fn, ar, ai, er, ei, + actual.real, actual.imag) + self.rAssertAlmostEqual(exr, actual.real, + abs_err=real_abs_err, + msg=error_message) + self.rAssertAlmostEqual(exi, actual.imag, + msg=error_message) + + except AssertionError as ex: + failures += 1 + if verbose : + print(ex) + except BaseException as ex: + failures += 1 + if verbose : + print(raised_fmt.format(id, fn, ar, ai, ex, er, ei)) + + if failures : + self.fail('{} discrepancies'.format(failures)) + def assertCISEqual(self, a, b): eps = 1E-7 @@ -446,6 +460,8 @@ self.assertTrue(math.isnan(abs(complex(2.3, NAN)))) self.assertEqual(abs(complex(INF, NAN)), INF) self.assertTrue(math.isnan(abs(complex(NAN, NAN)))) + + # result overflows if float.__getformat__("double").startswith("IEEE"): self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308)) diff --git a/Lib/test/test_float_jy.py b/Lib/test/test_float_jy.py --- a/Lib/test/test_float_jy.py +++ b/Lib/test/test_float_jy.py @@ -85,6 +85,13 @@ self.assert_(type(float('inf')), float) self.assertRaises(OverflowError, long, float('Infinity')) + def test_minus_zero(self): + # Some operations confused by -0.0 + mz = float('-0.0') + self.assertEquals(mz, 0.) + self.assertEquals(repr(mz)[0], '-') + self.assertEquals(repr(abs(mz))[0], '0') + def test_float_none(self): self.assertRaises(TypeError, float, None) diff --git a/Misc/make_cmath_testcases.py b/Misc/make_cmath_testcases.py --- a/Misc/make_cmath_testcases.py +++ b/Misc/make_cmath_testcases.py @@ -103,14 +103,24 @@ } def generate_cases() : - fmt = "{}{:04d} {} {!r} 0.0 -> {} 0.0" + fmt = "{}{:04d} {} {!r} 0.0 -> {} {!r}" for fn in sorted(cases_to_generate.keys()): print "-- Additional real values (Jython)" count, xlist = cases_to_generate[fn] for x in xlist: + # Compute the function (in the reference library) func = getattr(mpmath, fn) y = func(x) - print fmt.format(fn, count, fn, x, mpmath.nstr(y, 20) ) + # For the benefit of cmath tests, get the sign of imaginary zero right + zero = 0.0 + if math.copysign(1., x) > 0.: + if fn=='cos' : + zero = -0.0 + else : + if fn=='cosh' : + zero = -0.0 + # Output one test case at sufficient precision + print fmt.format(fn, count, fn, x, mpmath.nstr(y, 20), zero ) count += 1 def test_main(): diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -39,7 +39,8 @@ - [ 2252 ] Args in sys.argv are now unicode if characters > 127 - [ 2092 ] Upgrade to JLine2 and add tab completion support - [ 2236 ] Interactive parser does not accept try ... except E as e: syntax - - [ 2237 ] More robust math/cmath support (ongoing) + - [ 2237 ] Fully conformant math and cmath support + - [ 2244 ] More robust testing of math and cmath modules New features - Full support of Python buffer protocol, along with Java ByteBuffer support diff --git a/src/org/python/core/PyFloat.java b/src/org/python/core/PyFloat.java --- a/src/org/python/core/PyFloat.java +++ b/src/org/python/core/PyFloat.java @@ -839,10 +839,7 @@ @ExposedMethod(doc = BuiltinDocs.float___abs___doc) final PyObject float___abs__() { - if (getValue() < 0) { - return float___neg__(); - } - return float___float__(); + return new PyFloat(Math.abs(getValue())); } @Override diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -2,6 +2,7 @@ import org.python.core.Py; import org.python.core.PyComplex; +import org.python.core.PyException; import org.python.core.PyFloat; import org.python.core.PyInstance; import org.python.core.PyObject; @@ -12,48 +13,21 @@ public static final PyFloat pi = new PyFloat(Math.PI); public static final PyFloat e = new PyFloat(Math.E); - private static final PyComplex one = new PyComplex(1.0, 0.0); - private static final PyComplex half = new PyComplex(0.5, 0.0); - private static final PyComplex i = new PyComplex(0.0, 1.0); - private static final PyComplex half_i = new PyComplex(0.0, 0.5); - /** 2 (Ref: Abramowitz & Stegun [1972], p2). */ private static final double ROOT_HALF = 0.70710678118654752440; + /** ln({@link Double#MAX_VALUE}) or a little less */ + private static final double NEARLY_LN_DBL_MAX = 709.4361393; + /** + * For x larger than this, e-x is negligible compared with + * ex, or equivalently 1 is negligible compared with e2x, in + * IEEE-754 floating point. Beyond this, sinh x and cosh x are adequately + * approximated by 0.5ex. The smallest theoretical value is 27 ln(2). + */ + private static final double ATLEAST_27LN2 = 18.72; + private static final double HALF_E2 = 0.5 * Math.E * Math.E; - private static PyComplex c_prodi(PyComplex x) { - return (PyComplex)x.__mul__(i); - } - - private static boolean isNaN(PyComplex x) { - return Double.isNaN(x.real) || Double.isNaN(x.imag); - } - - private static double abs(PyComplex x) { - boolean isNaN = isNaN(x); - boolean isInfinite = !isNaN && (Double.isInfinite(x.real) || Double.isInfinite(x.imag)); - if (isNaN) { - return Double.NaN; - } - if (isInfinite) { - return Double.POSITIVE_INFINITY; - } - double real_abs = Math.abs(x.real); - double imag_abs = Math.abs(x.imag); - - if (real_abs < imag_abs) { - if (x.imag == 0.0) { - return real_abs; - } - double q = x.real / x.imag; - return imag_abs * Math.sqrt(1 + q * q); - } else { - if (x.real == 0.0) { - return imag_abs; - } - double q = x.imag / x.real; - return real_abs * Math.sqrt(1 + q * q); - } - } + /** log10e (Ref: Abramowitz & Stegun [1972], p3). */ + private static final double LOG10E = 0.43429448190325182765; private static PyComplex complexFromPyObject(PyObject obj) { // If op is already of type PyComplex_Type, return its value @@ -88,74 +62,555 @@ return new PyComplex(obj.asDouble(), 0); } - public static PyObject acos(PyObject in) { - PyComplex x = complexFromPyObject(in); - return c_prodi(log(x.__add__(i.__mul__(sqrt(one.__sub__(x.__mul__(x))))))).__neg__(); + /** + * Return the arc cosine of w. There are two branch cuts. One extends right from 1 along the + * real axis to ∞, continuous from below. The other extends left from -1 along the real + * axis to -∞, continuous from above. + * + * @param w + * @return cos-1w + */ + public static PyComplex acos(PyObject w) { + return _acos(complexFromPyObject(w)); } - public static PyComplex acosh(PyObject in) { - PyComplex x = complexFromPyObject(in); - PyComplex a = sqrt(x.__sub__(one)); - PyComplex b = sqrt(x.__add__(one)); - PyComplex c = sqrt(half); - PyComplex r = log(c.__mul__(b.__add__(a))); - return ((PyComplex)r.__add__(r)); + /** + * Helper to compute cos-1w. The method used is as in CPython: + *

+ * a = (1-w)½ = √2 sin z/2
+ * b = (1+w)½ = √2 cos z/2 + *

+ * Then, with z = x+iy, a = a1+ia2, and b = + * b1+ib2, + *

+ * a1 / b1 = tan x/2
+ * a2b1 - a1b2 = sinh y + *

+ * and we use {@link Math#atan2(double, double)} and {@link math#asinh(double)} to obtain + * x and y. + *

+ * For w sufficiently large that w2≫1, cos-1w + * ≈ -i ln(2w). + * + * @param w + * @return cos-1w + */ + private static PyComplex _acos(PyComplex w) { + + // Let z = x + iy and w = u + iv. + double x, y, u = w.real, v = w.imag; + + if (Math.abs(u) > 0x1p27 || Math.abs(v) > 0x1p27) { + /* + * w is large: approximate 2cos(z) by exp(i(x+iy)) or exp(-i(x+iy)), whichever + * dominates. Hence, z = x+iy = i ln(2(u+iv)) or -i ln(2(u+iv)) + */ + x = Math.atan2(Math.abs(v), u); + y = Math.copySign(logHypot(u, v) + math.LN2, -v); + + } else if (Double.isNaN(v)) { + // Special cases + x = (u == 0.) ? Math.PI / 2. : v; + y = v; + + } else { + // Normal case, without risk of overflow. + PyComplex a = sqrt(new PyComplex(1. - u, -v)); // a = sqrt(1-w) = sqrt(2) sin(z/2) + PyComplex b = sqrt(new PyComplex(1 + u, v)); // b = sqrt(1+w) = sqrt(2) cos(z/2) + // Arguments here are sin(x/2)cosh(y/2), cos(x/2)cosh(y/2) giving tan(x/2) + x = 2. * Math.atan2(a.real, b.real); + // 2 (cos(x/2)**2+sin(x/2)**2) sinh(y/2)cosh(y/2) = sinh y + y = math.asinh(a.imag * b.real - a.real * b.imag); + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(new PyComplex(x, y), w); } - public static PyComplex asin(PyObject in) { - PyComplex x = complexFromPyObject(in); - PyComplex squared = (PyComplex)x.__mul__(x); - PyComplex sq1_minus_xsq = sqrt(one.__sub__(squared)); - return (PyComplex)c_prodi(log(sq1_minus_xsq.__add__(c_prodi(x)))).__neg__(); + /** + * Return the hyperbolic arc cosine of w. There is one branch cut, extending left from 1 along + * the real axis to -∞, continuous from above. + * + * @param w + * @return cosh-1w + */ + public static PyComplex acosh(PyObject w) { + return _acosh(complexFromPyObject(w)); } - public static PyComplex asinh(PyObject in) { - PyComplex x = complexFromPyObject(in); - PyComplex a = sqrt(x.__add__(i)); - PyComplex b = sqrt(x.__sub__(i)); - PyComplex z = sqrt(half); - PyComplex r = log(z.__mul__(a.__add__(b))); - return ((PyComplex)r.__add__(r)); + /** + * Helper to compute z = cosh-1w. The method used is as in CPython: + *

+ * a = (w-1)½ = √2 sinh z/2
+ * b = (w+1)½ = √2 cosh z/2 + *

+ * Then, with z = x+iy, a = a1+ia2, and b = + * b1+ib2, + *

+ * a1b1 + a2b2 = sinh x
+ * a2 / b1 = tan y/2 + *

+ * and we use {@link math#asinh(double)} and {@link Math#atan2(double, double)} to obtain + * x and y. + *

+ * For w sufficiently large that w2≫1, + * cosh-1w ≈ ln(2w). We do not use this method also to compute + * cos-1w, because the branch cuts do not correspond. + * + * @param w + * @return cosh-1w + */ + private static PyComplex _acosh(PyComplex w) { + + // Let z = x + iy and w = u + iv. + double x, y, u = w.real, v = w.imag; + + if (Math.abs(u) > 0x1p27 || Math.abs(v) > 0x1p27) { + /* + * w is large: approximate 2cosh(z) by exp(x+iy) or exp(-x-iy), whichever dominates. + * Hence, z = x+iy = ln(2(u+iv)) or -ln(2(u+iv)) + */ + x = logHypot(u, v) + math.LN2; + y = Math.atan2(v, u); + + } else if (v == 0. && !Double.isNaN(u)) { + /* + * We're on the real axis (and maybe the branch cut). u = cosh x cos y. In all cases, + * the sign of y follows v. + */ + if (u >= 1.) { + // As real library, cos y = 1, u = cosh x. + x = math.acosh(u); + y = v; + } else if (u < -1.) { + // Left part of cut: cos y = -1, u = -cosh x + x = math.acosh(-u); + y = Math.copySign(Math.PI, v); + } else { + // -1 <= u <= 1: cosh x = 1, u = cos y. + x = 0.; + y = Math.copySign(Math.acos(u), v); + } + + } else { + // Normal case, without risk of overflow. + PyComplex a = sqrt(new PyComplex(u - 1., v)); // a = sqrt(w-1) = sqrt(2) sinh(z/2) + PyComplex b = sqrt(new PyComplex(u + 1., v)); // b = sqrt(w+1) = sqrt(2) cosh(z/2) + // 2 sinh(x/2)cosh(x/2) (cos(y/2)**2+sin(y/2)**2) = sinh x + x = math.asinh(a.real * b.real + a.imag * b.imag); + // Arguments here are cosh(x/2)sin(y/2) and cosh(x/2)cos(y/2) giving tan y/2 + y = 2. * Math.atan2(a.imag, b.real); + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(new PyComplex(x, y), w); } - public static PyComplex atan(PyObject in) { - PyComplex x = complexFromPyObject(in); - return (PyComplex)half_i.__mul__(log(i.__add__(x).__div__(i.__sub__(x)))); + /** + * Return the arc sine of w. There are two branch cuts. One extends right from 1 along the real + * axis to ∞, continuous from below. The other extends left from -1 along the real axis to + * -∞, continuous from above. + * + * @param w + * @return sin-1w + */ + public static PyComplex asin(PyObject w) { + return asinOrAsinh(complexFromPyObject(w), false); } - public static PyComplex atanh(PyObject in) { - PyComplex x = complexFromPyObject(in); - return (PyComplex)half.__mul__(log(one.__add__(x).__div__(one.__sub__(x)))); + /** + * Return the hyperbolic arc sine of w. There are two branch cuts. One extends from 1j along the + * imaginary axis to ∞j, continuous from the right. The other extends from -1j along the + * imaginary axis to -∞j, continuous from the left. + * + * @param w + * @return sinh-1w + */ + public static PyComplex asinh(PyObject w) { + return asinOrAsinh(complexFromPyObject(w), true); } - public static PyComplex cos(PyObject in) { - PyComplex x = complexFromPyObject(in); - return new PyComplex(Math.cos(x.real) * math.cosh(x.imag), -Math.sin(x.real) - * math.sinh(x.imag)); + /** + * Helper to compute either sin-1w or sinh-1w. The method + * used is as in CPython: + *

+ * a = (1-iw)½ = √2 sin(π/4-iz/2)
+ * b = (1+iw)½ = √2 cos(π/4-iz/2) + *

+ * Then, with w = u+iv, z = x+iy, a = a1+ia2, and + * b = b1+ib2, + *

+ * a1b2 - a2b2 = sinh x
+ * v / (a2b1 - a1b2) = tan y + *

+ * and we use {@link math#asinh(double)} and {@link Math#atan2(double, double)} to obtain + * x and y. + *

+ * For w sufficiently large that w2≫1, + * sinh-1w ≈ ln(2w). When computing sin-1w, we + * evaluate -i sinh-1iw instead. + * + * @param w + * @param h true to compute sinh-1w, false to + * compute sin-1w. + * @return sinh-1w or sin-1w + */ + private static PyComplex asinOrAsinh(PyComplex w, boolean h) { + double u, v, x, y; + PyComplex z; + + if (h) { + // We compute z = asinh(w). Let z = x + iy and w = u + iv. + u = w.real; + v = w.imag; + // Then the function body computes x + iy = asinh(w). + } else { + // We compute w = asin(z). Unusually, let w = u - iv, so u + iv = iw. + v = w.real; + u = -w.imag; + // Then as before, the function body computes asinh(u+iv) = asinh(iw) = i asin(w), + // but we finally return z = y - ix = -i asinh(iw) = asin(w). + } + + if (Double.isNaN(u)) { + // Special case for nan in real part. Default clause deals naturally with v=nan. + if (v == 0.) { + x = u; + y = v; + } else if (Double.isInfinite(v)) { + x = Double.POSITIVE_INFINITY; + y = u; + } else { // Any other value of v -> nan+nanj + x = y = u; + } + + } else if (Math.abs(u) > 0x1p27 || Math.abs(v) > 0x1p27) { + /* + * w is large: approximate 2sinh(z) by exp(x+iy) or -exp(-x-iy), whichever dominates. + * Hence, z = x+iy = ln(2(u+iv)) or -ln(-2(u+iv)) + */ + x = logHypot(u, v) + math.LN2; + if (Math.copySign(1., u) > 0.) { + y = Math.atan2(v, u); + } else { + // Adjust for sign, choosing the angle so that -pi/2 < y < pi/2 + x = -x; + y = Math.atan2(v, -u); + } + + } else { + // Normal case, without risk of overflow. + PyComplex a = sqrt(new PyComplex(1. + v, -u)); // a = sqrt(1-iw) + PyComplex b = sqrt(new PyComplex(1. - v, u)); // b = sqrt(1+iw) + // Combine the parts so as that terms in y cancel, leaving us with sinh x: + x = math.asinh(a.real * b.imag - a.imag * b.real); + // The arguments are v = cosh x sin y, and cosh x cos y + y = Math.atan2(v, a.real * b.real - a.imag * b.imag); + } + + // Compose the result w according to whether we're computing asin(w) or asinh(w). + if (h) { + z = new PyComplex(x, y); // z = x + iy = asinh(u+iv). + } else { + z = new PyComplex(y, -x); // z = y - ix = -i asinh(v-iu) = asin(w) + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(z, w); } - public static PyComplex cosh(PyObject in) { - PyComplex x = complexFromPyObject(in); - return new PyComplex(Math.cos(x.imag) * math.cosh(x.real), Math.sin(x.imag) - * math.sinh(x.real)); + /** + * Return the arc tangent of w. There are two branch cuts. One extends from 1j along the + * imaginary axis to ∞j, continuous from the right. The other extends from -1j along the + * imaginary axis to -∞j, continuous from the left. + * + * @param w + * @return tan-1w + */ + public static PyComplex atan(PyObject w) { + return atanOrAtanh(complexFromPyObject(w), false); } - public static PyComplex exp(PyObject in) { - PyComplex x = complexFromPyObject(in); - double l = Math.exp(x.real); - return new PyComplex(l * Math.cos(x.imag), l * Math.sin(x.imag)); + /** + * Return the hyperbolic arc tangent of w. There are two branch cuts. One extends from 1 along + * the real axis to ∞, continuous from below. The other extends from -1 along the real + * axis to -∞, continuous from above. + * + * @param w + * @return tanh-1w + */ + public static PyComplex atanh(PyObject w) { + return atanOrAtanh(complexFromPyObject(w), true); } - public static PyComplex log(PyObject in) { - PyComplex x = complexFromPyObject(in); - if (isNaN(x)) { - if (Double.isInfinite(x.real) || Double.isInfinite(x.imag)) { - return new PyComplex(Double.POSITIVE_INFINITY, Double.NaN); + /** + * Helper to compute either tan-1w or tanh-1w. The method + * used is close to that used in CPython. For z = tanh-1w: + *

+ * z = ½ln(1 + 2w/(1-w)) + *

+ * Then, letting z = x+iy, and w = u+iv, + *

+ * x = ¼ln(1 + 4u/((1-u)2+v2)) = + * -¼ln(1 - 4u/((1+u)2+v2))
+ * y = ½tan-1(2v / ((1+u)(1-u)-v2))
+ *

+ * We use {@link math#log1p(double)} and {@link Math#atan2(double, double)} to obtain x + * and y. The second expression for x is used when u<0. For + * w sufficiently large that w2≫1, tanh-1w + * ≈ 1/w ± iπ/2). For small w, tanh-1w ≈ + * w. When computing tan-1w, we evaluate -i + * tanh-1iw instead. + * + * @param w + * @param h true to compute tanh-1w, false to + * compute tan-1w. + * @return tanh-1w or tan-1w + */ + private static PyComplex atanOrAtanh(PyComplex w, boolean h) { + double u, v, x, y; + PyComplex z; + + if (h) { + // We compute z = atanh(w). Let z = x + iy and w = u + iv. + u = w.real; + v = w.imag; + // Then the function body computes x + iy = atanh(w). + } else { + // We compute w = atan(z). Unusually, let w = u - iv, so u + iv = iw. + v = w.real; + u = -w.imag; + // Then as before, the function body computes atanh(u+iv) = atanh(iw) = i atan(w), + // but we finally return z = y - ix = -i atanh(iw) = atan(w). + } + + double absu = Math.abs(u), absv = Math.abs(v); + + if (absu >= 0x1p511 || absv >= 0x1p511) { + // w is large: approximate atanh(w) by 1/w + i pi/2. 1/w = conjg(w)/|w|**2. + if (Double.isInfinite(absu) || Double.isInfinite(absv)) { + x = Math.copySign(0., u); } else { - return PyComplex.NaN; + // w is also too big to square, carry a 2**-N scaling factor. + int N = 520; + double uu = Math.scalb(u, -N), vv = Math.scalb(v, -N); + double mod2w = uu * uu + vv * vv; + x = Math.scalb(uu / mod2w, -N); + } + // We don't need the imaginary part of 1/z. Just pi/2 with the sign of v. (If not nan.) + if (Double.isNaN(v)) { + y = v; + } else { + y = Math.copySign(Math.PI / 2., v); + } + + } else if (absu < 0x1p-53) { + // u is small enough that u**2 may be neglected relative to 1. + if (absv > 0x1p-27) { + // v is not small, but is not near overflow either. + double v2 = v * v; + double d = 1. + v2; + x = Math.copySign(Math.log1p(4. * absu / d), u) * 0.25; + y = Math.atan2(2. * v, 1. - v2) * 0.5; + } else { + // v is also small enough that v**2 may be neglected (or is nan). So z = w. + x = u; + y = v; + } + + } else if (absu == 1. && absv < 0x1p-27) { + // w is close to +1 or -1: needs a different expression, good as v->0 + x = Math.copySign(Math.log(absv) - math.LN2, u) * 0.5; + if (v == 0.) { + y = Double.NaN; + } else { + y = Math.copySign(Math.atan2(2., absv), v) * 0.5; + } + + } else { + /* + * Normal case, without risk of overflow. The basic expression is z = + * 0.5*ln((1+w)/(1-w)), which for positive u we rearrange as 0.5*ln(1+2w/(1-w)) and for + * negative u as -0.5*ln(1-2w/(1+w)). By use of absu, we reduce the difference between + * the expressions fo u>=0 and u<0 to a sign transfer. + */ + double lmu = (1. - absu), lpu = (1. + absu), v2 = v * v; + double d = lmu * lmu + v2; + x = Math.copySign(Math.log1p(4. * absu / d), u) * 0.25; + y = Math.atan2(2. * v, lmu * lpu - v2) * 0.5; + } + + // Compose the result w according to whether we're computing atan(w) or atanh(w). + if (h) { + z = new PyComplex(x, y); // z = x + iy = atanh(u+iv). + } else { + z = new PyComplex(y, -x); // z = y - ix = -i atanh(v-iu) = atan(w) + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(z, w); + } + + /** + * Return the cosine of z. + * + * @param z + * @return cos z + */ + public static PyComplex cos(PyObject z) { + return cosOrCosh(complexFromPyObject(z), false); + } + + /** + * Return the hyperbolic cosine of z. + * + * @param z + * @return cosh z + */ + public static PyComplex cosh(PyObject z) { + return cosOrCosh(complexFromPyObject(z), true); + } + + /** + * Helper to compute either cos z or cosh z. + * + * @param z + * @param h true to compute cosh z, false to compute cos + * z. + * @return + */ + private static PyComplex cosOrCosh(PyComplex z, boolean h) { + double x, y, u, v; + PyComplex w; + + if (h) { + // We compute w = cosh(z). Let w = u + iv and z = x + iy. + x = z.real; + y = z.imag; + // Then the function body computes cosh(x+iy), according to: + // u = cosh(x) cos(y), + // v = sinh(x) sin(y), + // And we return w = u + iv. + } else { + // We compute w = sin(z). Unusually, let z = y - ix, so x + iy = iz. + y = z.real; + x = -z.imag; + // Then the function body computes cosh(x+iy) = cosh(iz) = cos(z) as before. + } + + if (y == 0.) { + // Real argument for cosh (or imaginary for cos): use real library. + u = math.cosh(x); // This will raise a range error on overflow. + // v is zero but follows the sign of x*y (in which y could be -0.0). + v = Math.copySign(1., x) * y; + + } else if (x == 0.) { + // Imaginary argument for cosh (or real for cos): imaginary result at this point. + u = Math.cos(y); + // v is zero but follows the sign of x*y (in which x could be -0.0). + v = x * Math.copySign(1., y); + + } else { + + // The trig calls will not throw, although if y is infinite, they return nan. + double cosy = Math.cos(y), siny = Math.sin(y), absx = Math.abs(x); + + if (absx == Double.POSITIVE_INFINITY) { + if (!Double.isNaN(cosy)) { + // w = (inf,inf), but "rotated" by the direction cosines. + u = absx * cosy; + v = x * siny; + } else { + // Provisionally w = (inf,nan), which will raise domain error if y!=nan. + u = absx; + v = Double.NaN; + } + + } else if (absx > ATLEAST_27LN2) { + // Use 0.5*e**x approximation. This is also the region where we risk overflow. + double r = Math.exp(absx - 2.); + // r approximates 2cosh(x)/e**2: multiply in this order to avoid inf: + u = r * cosy * HALF_E2; + // r approximates 2sinh(|x|)/e**2: put back the proper sign of x in passing. + v = Math.copySign(r, x) * siny * HALF_E2; + if (Double.isInfinite(u) || Double.isInfinite(v)) { + // A finite x gave rise to an infinite u or v. + throw math.mathRangeError(); + } + + } else { + // Normal case, without risk of overflow. + u = Math.cosh(x) * cosy; + v = Math.sinh(x) * siny; } } - return new PyComplex(Math.log(abs(x)), Math.atan2(x.imag, x.real)); + + // Compose the result w = u + iv. + w = new PyComplex(u, v); + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(w, z); + } + + /** + * Return the exponential value ez. + * + * @param z + * @return ez + */ + public static PyComplex exp(PyObject z) { + PyComplex zz = complexFromPyObject(z); + double x = zz.real, y = zz.imag, r, u, v; + /* + * This has a lot of corner-cases, and some of them make little sense sense, but it matches + * CPython and passes the regression tests. + */ + if (y == 0.) { + // Real value: use a real solution. (This may raise a range error.) + u = math.exp(x); + // v follows sign of y. + v = y; + + } else { + // The trig calls will not throw, although if y is infinite, they return nan. + double cosy = Math.cos(y), siny = Math.sin(y); + + if (x == Double.NEGATIVE_INFINITY) { + // w = (0,0) but "signed" by the direction cosines (even in they are nan). + u = Math.copySign(0., cosy); + v = Math.copySign(0., siny); + + } else if (x == Double.POSITIVE_INFINITY) { + if (!Double.isNaN(cosy)) { + // w = (inf,inf), but "signed" by the direction cosines. + u = Math.copySign(x, cosy); + v = Math.copySign(x, siny); + } else { + // Provisionally w = (inf,nan), which will raise domain error if y!=nan. + u = x; + v = Double.NaN; + } + + } else if (x > NEARLY_LN_DBL_MAX) { + // r = e**x would overflow but maybe not r*cos(y) and r*sin(y). + r = Math.exp(x - 1); // = r / e + u = r * cosy * Math.E; + v = r * siny * Math.E; + if (Double.isInfinite(u) || Double.isInfinite(v)) { + // A finite x gave rise to an infinite u or v. + throw math.mathRangeError(); + } + + } else { + // Normal case, without risk of overflow. + // Compute r = exp(x), and return w = u + iv = r (cos(y) + i*sin(y)) + r = Math.exp(x); + u = r * cosy; + v = r * siny; + } + } + // If that generated a nan, and there wasn't one in the argument, raise domain error. + return exceptNaN(new PyComplex(u, v), zz); } public static double phase(PyObject in) { @@ -170,25 +625,42 @@ return new PyTuple(new PyFloat(r), new PyFloat(phi)); } + /** + * Return the complex number x with polar coordinates r and phi. Equivalent to + * r * (math.cos(phi) + math.sin(phi)*1j). + * + * @param r radius + * @param phi angle + * @return + */ public static PyComplex rect(double r, double phi) { - // Handle various edge cases + double x, y; + if (Double.isInfinite(r) && (Double.isInfinite(phi) || Double.isNaN(phi))) { - return new PyComplex(Double.POSITIVE_INFINITY, Double.NaN); + x = Double.POSITIVE_INFINITY; + y = Double.NaN; + + } else if (phi == 0.0) { + // cos(phi)=1, sin(phi)=phi: finesse oddball r in computing y, but not x. + x = r; + if (Double.isNaN(r)) { + y = phi; + } else if (Double.isInfinite(r)) { + y = phi * Math.copySign(1., r); + } else { + y = phi * r; + } + + } else if (r == 0.0 && (Double.isInfinite(phi) || Double.isNaN(phi))) { + // Ignore any problems (inf, nan) with phi + x = y = 0.; + + } else { + // Text-book case, using the trig functions. + x = r * Math.cos(phi); + y = r * Math.sin(phi); } - if (phi == 0.0) { // NB this test will succeed if phi is 0.0 or -0.0 - if (Double.isNaN(r)) { - return new PyComplex(Double.NaN, 0.0); - } else if (r == Double.POSITIVE_INFINITY) { - return new PyComplex(r, phi); - } else if (r == Double.NEGATIVE_INFINITY) { - return new PyComplex(r, -phi); - } - } - if (r == 0.0 && (Double.isInfinite(phi) || Double.isNaN(phi))) { - return new PyComplex(0.0, 0.0); - } - - return new PyComplex(r * Math.cos(phi), r * Math.sin(phi)); + return exceptNaN(new PyComplex(x, y), r, phi); } /** @@ -211,48 +683,231 @@ return Double.isNaN(x.real) || Double.isNaN(x.imag); } - public static PyComplex log10(PyObject in) { - PyComplex x = complexFromPyObject(in); - if (isNaN(x)) { - if (Double.isInfinite(x.real) || Double.isInfinite(x.imag)) { - return new PyComplex(Double.POSITIVE_INFINITY, Double.NaN); + /** + * Returns the natural logarithm of w. + * + * @param w + * @return ln w + */ + public static PyComplex log(PyObject w) { + PyComplex ww = complexFromPyObject(w); + double u = ww.real, v = ww.imag; + // The real part of the result is the log of the magnitude. + double lnr = logHypot(u, v); + // The imaginary part of the result is the arg. This may result in a nan. + double theta = Math.atan2(v, u); + PyComplex z = new PyComplex(lnr, theta); + return exceptNaN(z, ww); + } + + /** + * Returns the common logarithm of w (base 10 logarithm). + * + * @param w + * @return log10w + */ + public static PyComplex log10(PyObject w) { + PyComplex ww = complexFromPyObject(w); + double u = ww.real, v = ww.imag; + // The expression is the same as for base e, scaled in magnitude. + double logr = logHypot(u, v) * LOG10E; + double theta = Math.atan2(v, u) * LOG10E; + PyComplex z = new PyComplex(logr, theta); + return exceptNaN(z, ww); + } + + /** + * Returns the logarithm of w to the given base. If the base is not specified, returns + * the natural logarithm of w. There is one branch cut, from 0 along the negative real + * axis to -∞, continuous from above. + * + * @param w + * @param b + * @return logbw + */ + public static PyComplex log(PyObject w, PyObject b) { + PyComplex ww = complexFromPyObject(w), bb = complexFromPyObject(b), z; + double u = ww.real, v = ww.imag, br = bb.real, bi = bb.imag, x, y; + // Natural log of w is (x,y) + x = logHypot(u, v); + y = Math.atan2(v, u); + + if (bi != 0. || br <= 0.) { + // Complex or negative real base requires complex log: general case. + PyComplex lnb = log(bb); + z = (PyComplex)(new PyComplex(x, y)).__div__(lnb); + + } else { + // Real positive base: frequent case. (b = inf or nan ends up here too.) + double lnb = Math.log(br); + z = new PyComplex(x / lnb, y / lnb); + } + + return exceptNaN(z, ww); + } + + /** + * Helper function for the log of a complex number, dealing with the log magnitude, and without + * intermediate overflow or underflow. It returns ln r, where r2 = + * u2+v2. To do this it computes + * ½ln(u2+v2). Special cases are handled as follows: + *

    + *
  • if u or v is NaN, it returns NaN
  • + *
  • if u or v is infinite, it returns positive infinity
  • + *
  • if u and v are both zero, it raises a ValueError
  • + *
+ * We have this function instead of Math.log(Math.hypot(u,v)) because a valid + * result is still possible even when hypot(u,v) overflows, and because there's no + * point in taking a square root when a log is to follow. + * + * @param u + * @param v + * @return ½ln(u2+v2) + */ + private static double logHypot(double u, double v) { + + if (Double.isInfinite(u) || Double.isInfinite(v)) { + return Double.POSITIVE_INFINITY; + + } else { + // Cannot overflow, but if u=v=0 will return -inf. + int scale = 0, ue = Math.getExponent(u), ve = Math.getExponent(v); + double lnr; + + if (ue < -511 && ve < -511) { + // Both u and v are too small to square, or zero. (Just one would be ok.) + scale = 600; + } else if (ue > 510 || ve > 510) { + // One of these is too big to square and double (or is nan or inf). + scale = -600; + } + + if (scale == 0) { + // Normal case: there is no risk of overflow or log of zero. + lnr = 0.5 * Math.log(u * u + v * v); } else { - return PyComplex.NaN; + // We must work with scaled values, us = u * 2**n etc.. + double us = Math.scalb(u, scale); + double vs = Math.scalb(v, scale); + // rs**2 = r**2 * 2**2n + double rs2 = us * us + vs * vs; + // So ln(r) = ln(u**2+v**2)/2 = ln(us**2+vs**2)/2 - n ln(2) + lnr = 0.5 * Math.log(rs2) - scale * math.LN2; + } + + // (u,v) = 0 leads to ln(r) = -inf, but that's a domain error + if (lnr == Double.NEGATIVE_INFINITY) { + throw math.mathDomainError(); + } else { + return lnr; } } - double l = abs(x); - return new PyComplex(math.log10(new PyFloat(l)), Math.atan2(x.imag, x.real) - / Math.log(10.0)); } - public static PyComplex log(PyObject in, PyObject base) { - return log(complexFromPyObject(in), complexFromPyObject(base)); + /** + * Return the sine of z. + * + * @param z + * @return sin z + */ + public static PyComplex sin(PyObject z) { + return sinOrSinh(complexFromPyObject(z), false); } - public static PyComplex log(PyComplex x, PyComplex base) { - if (isNaN(x)) { - if (Double.isInfinite(x.real) || Double.isInfinite(x.imag)) { - return new PyComplex(Double.POSITIVE_INFINITY, Double.NaN); + /** + * Return the hyperbolic sine of z. + * + * @param z + * @return sinh z + */ + public static PyComplex sinh(PyObject z) { + return sinOrSinh(complexFromPyObject(z), true); + } + + /** + * Helper to compute either sin z or sinh z. + * + * @param z + * @param h true to compute sinh z, false to compute sin + * z. + * @return + */ + private static PyComplex sinOrSinh(PyComplex z, boolean h) { + double x, y, u, v; + PyComplex w; + + if (h) { + // We compute w = sinh(z). Let w = u + iv and z = x + iy. + x = z.real; + y = z.imag; + // Then the function body computes sinh(x+iy), according to: + // u = sinh(x) cos(y), + // v = cosh(x) sin(y), + // And we return w = u + iv. + } else { + // We compute w = sin(z). Unusually, let z = y - ix, so x + iy = iz. + y = z.real; + x = -z.imag; + // Then as before, the function body computes sinh(x+iy) = sinh(iz) = i sin(z), + // but we finally return w = v - iu = sin(z). + } + + if (y == 0.) { + // Real argument for sinh (or imaginary for sin): use real library. + u = math.sinh(x); // This will raise a range error on overflow. + // v follows the sign of y (which could be -0.0). + v = y; + + } else if (x == 0.) { + // Imaginary argument for sinh (or real for sin): imaginary result at this point. + v = Math.sin(y); + // u follows sign of x (which could be -0.0). + u = x; + + } else { + + // The trig calls will not throw, although if y is infinite, they return nan. + double cosy = Math.cos(y), siny = Math.sin(y), absx = Math.abs(x); + + if (absx == Double.POSITIVE_INFINITY) { + if (!Double.isNaN(cosy)) { + // w = (inf,inf), but "rotated" by the direction cosines. + u = x * cosy; + v = absx * siny; + } else { + // Provisionally w = (inf,nan), which will raise domain error if y!=nan. + u = x; + v = Double.NaN; + } + + } else if (absx > ATLEAST_27LN2) { + // Use 0.5*e**x approximation. This is also the region where we risk overflow. + double r = Math.exp(absx - 2.); + // r approximates 2cosh(x)/e**2: multiply in this order to avoid inf: + v = r * siny * HALF_E2; + // r approximates 2sinh(|x|)/e**2: put back the proper sign of x in passing. + u = Math.copySign(r, x) * cosy * HALF_E2; + if (Double.isInfinite(u) || Double.isInfinite(v)) { + // A finite x gave rise to an infinite u or v. + throw math.mathRangeError(); + } + } else { - return PyComplex.NaN; + // Normal case, without risk of overflow. + u = Math.sinh(x) * cosy; + v = Math.cosh(x) * siny; } } - double l = abs(x); - PyComplex log_base = log(base); - return (PyComplex)new PyComplex(math.log(new PyFloat(l)), Math.atan2(x.imag, x.real)) - .__div__(log_base); - } - public static PyComplex sin(PyObject in) { - PyComplex x = complexFromPyObject(in); - return new PyComplex(Math.sin(x.real) * math.cosh(x.imag), Math.cos(x.real) - * math.sinh(x.imag)); - } + // Compose the result w according to whether we're computing sin(z) or sinh(z). + if (h) { + w = new PyComplex(u, v); // w = u + iv = sinh(x+iy). + } else { + w = new PyComplex(v, -u); // w = v - iu = sin(y-ix) = sin(z) + } - public static PyComplex sinh(PyObject in) { - PyComplex x = complexFromPyObject(in); - return new PyComplex(Math.cos(x.imag) * math.sinh(x.real), Math.sin(x.imag) - * math.cosh(x.real)); + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(w, z); } /** @@ -365,35 +1020,143 @@ } } - public static PyComplex tan(PyObject in) { - PyComplex x = complexFromPyObject(in); - - double sr = Math.sin(x.real); - double cr = Math.cos(x.real); - double shi = math.sinh(x.imag); - double chi = math.cosh(x.imag); - double rs = sr * chi; - double is = cr * shi; - double rc = cr * chi; - double ic = -sr * shi; - double d = rc * rc + ic * ic; - - return new PyComplex(((rs * rc) + (is * ic)) / d, ((is * rc) - (rs * ic)) / d); + /** + * Return the tangent of z. + * + * @param z + * @return tan z + */ + public static PyComplex tan(PyObject z) { + return tanOrTanh(complexFromPyObject(z), false); } - public static PyComplex tanh(PyObject in) { - PyComplex x = complexFromPyObject(in); + /** + * Return the hyperbolic tangent of z. + * + * @param z + * @return tanh z + */ + public static PyComplex tanh(PyObject z) { + return tanOrTanh(complexFromPyObject(z), true); + } - double si = Math.sin(x.imag); - double ci = Math.cos(x.imag); - double shr = math.sinh(x.real); - double chr = math.cosh(x.real); - double rs = ci * shr; - double is = si * chr; - double rc = ci * chr; - double ic = si * shr; - double d = rc * rc + ic * ic; + /** + * Helper to compute either tan z or tanh z. The expression used is: + *

+ * tanh(x+iy) = (sinh x cosh x + i sin y cos y) / + * (sinh2x + cos2y) + *

+ * A simplification is made for x sufficiently large that e2|x|≫1 that + * deals satisfactorily with large or infinite x. When computing tan, we evaluate + * i tan iz instead, and the approximation applies to + * e2|y|≫1. + * + * @param z + * @param h true to compute tanh z, false to compute tan + * z. + * @return tan or tanh z + */ + private static PyComplex tanOrTanh(PyComplex z, boolean h) { + double x, y, u, v, s; + PyComplex w; - return new PyComplex(((rs * rc) + (is * ic)) / d, ((is * rc) - (rs * ic)) / d); + if (h) { + // We compute w = tanh(z). Let w = u + iv and z = x + iy. + x = z.real; + y = z.imag; + // Then the function body computes tanh(x+iy), according to: + // s = sinh**2 x + cos**2 y + // u = sinh x cosh x / s, + // v = sin y cos y / s, + // And we return w = u + iv. + } else { + // We compute w = tan(z). Unusually, let z = y - ix, so x + iy = iz. + y = z.real; + x = -z.imag; + // Then the function body computes tanh(x+iy) = tanh(iz) = i tan(z) as before, + // but we finally return w = v - iu = tan(z). + } + + if (y == 0.) { + // Real argument for tanh (or imaginary for tan). + u = Math.tanh(x); + // v is zero but follows the sign of y (which could be -0.0). + v = y; + + } else if (x == 0. && !Double.isNaN(y)) { + // Imaginary argument for tanh (or real for tan): imaginary result at this point. + v = Math.tan(y); // May raise domain error + // u is zero but follows sign of x (which could be -0.0). + u = x; + + } else { + // The trig calls will not throw, although if y is infinite, they return nan. + double cosy = Math.cos(y), siny = Math.sin(y), absx = Math.abs(x); + + if (absx > ATLEAST_27LN2) { + // e**2x is much greater than 1: exponential approximation to sinh and cosh. + s = 0.25 * Math.exp(2 * absx); + u = Math.copySign(1., x); + if (s == Double.POSITIVE_INFINITY) { + // Either x is inf or 2x is large enough to overflow exp(). v=0, but signed: + v = Math.copySign(0., siny * cosy); + } else { + v = siny * cosy / s; + } + + } else { + // Normal case: possible overflow in s near (x,y) = (0,pi/2) is harmless. + double sinhx = Math.sinh(x), coshx = Math.cosh(x); + s = sinhx * sinhx + cosy * cosy; + u = sinhx * coshx / s; + v = siny * cosy / s; + } + } + + // Compose the result w according to whether we're computing tan(z) or tanh(z). + if (h) { + w = new PyComplex(u, v); // w = u + iv = tanh(x+iy). + } else { + w = new PyComplex(v, -u); // w = v - iu = tan(y-ix) = tan(z) + } + + // If that generated a nan, and there wasn't one in the argument, raise a domain error. + return exceptNaN(w, z); } + + /** + * Turn a NaN result into a thrown ValueError, a math domain error, if + * the original argument was not itself NaN. A PyComplex is a + * NaN if either component is a NaN. + * + * @param result to return (if we return) + * @param arg to include in check + * @return result if arg was NaN or result was not + * NaN + * @throws PyException (ValueError) if result was NaN and + * arg was not NaN + */ + private static PyComplex exceptNaN(PyComplex result, PyComplex arg) throws PyException { + if ((Double.isNaN(result.real) || Double.isNaN(result.imag)) + && !(Double.isNaN(arg.real) || Double.isNaN(arg.imag))) { + throw math.mathDomainError(); + } else { + return result; + } + } + + /** + * Raise ValueError if result is a NaN, but neither + * a nor b is NaN. Same as + * {@link #exceptNaN(PyComplex, PyComplex)}. + */ + private static PyComplex exceptNaN(PyComplex result, double a, double b) throws PyException { + if ((Double.isNaN(result.real) || Double.isNaN(result.imag)) + && !(Double.isNaN(a) || Double.isNaN(b))) { + throw math.mathDomainError(); + } else { + return result; + } + } + } diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java --- a/src/org/python/modules/math.java +++ b/src/org/python/modules/math.java @@ -24,7 +24,7 @@ private static final double MINUS_ONE = -1.0; private static final double TWO = 2.0; private static final double EIGHT = 8.0; - private static final double LN2 = 0.693147180559945309417232121458; // Ref OEIS A002162 + static final double LN2 = 0.693147180559945309417232121458; // Ref OEIS A002162 private static final double INF = Double.POSITIVE_INFINITY; private static final double NINF = Double.NEGATIVE_INFINITY; @@ -515,7 +515,7 @@ * * @return ValueError("math domain error") */ - private static PyException mathDomainError() { + static PyException mathDomainError() { return Py.ValueError("math domain error"); } @@ -524,7 +524,7 @@ * * @return OverflowError("math range error") */ - private static PyException mathRangeError() { + static PyException mathRangeError() { return Py.OverflowError("math range error"); } @@ -575,7 +575,7 @@ */ private static double exceptInf(double result, double arg) { if (Double.isInfinite(result) && !Double.isInfinite(arg)) { - throw Py.OverflowError("math range error"); + throw mathRangeError(); } else { return result; } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 21 05:25:37 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Wed, 21 Jan 2015 04:25:37 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Merge_some_upstream_changes?= =?utf-8?q?=2E?= Message-ID: <20150121042525.104124.57061@psf.io> https://hg.python.org/jython/rev/6543a4a393fe changeset: 7554:6543a4a393fe user: Frank Wierzbicki date: Wed Jan 21 04:25:24 2015 +0000 summary: Merge some upstream changes. files: Lib/test/test_codeop.py | 40 ++++++++++------------------ 1 files changed, 15 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_codeop.py b/Lib/test/test_codeop.py --- a/Lib/test/test_codeop.py +++ b/Lib/test/test_codeop.py @@ -37,20 +37,20 @@ ctx = {'a': 2} d = { 'value': eval(code,ctx) } r = { 'value': eval(str,ctx) } - self.assertEquals(unify_callables(r),unify_callables(d)) + self.assertEqual(unify_callables(r),unify_callables(d)) else: expected = compile(str, "", symbol, PyCF_DONT_IMPLY_DEDENT) - self.assertEquals( compile_command(str, "", symbol), expected) + self.assertEqual(compile_command(str, "", symbol), expected) def assertIncomplete(self, str, symbol='single'): '''succeed iff str is the start of a valid piece of code''' - self.assertEquals( compile_command(str, symbol=symbol), None) + self.assertEqual(compile_command(str, symbol=symbol), None) def assertInvalid(self, str, symbol='single', is_syntax=1): '''succeed iff str is the start of an invalid piece of code''' try: compile_command(str,symbol=symbol) - self.fail("No exception thrown for invalid code") + self.fail("No exception raised for invalid code") except SyntaxError: self.assertTrue(is_syntax) except OverflowError: @@ -61,12 +61,12 @@ # special case if not is_jython: - self.assertEquals(compile_command(""), - compile("pass", "", 'single', - PyCF_DONT_IMPLY_DEDENT)) - self.assertEquals(compile_command("\n"), - compile("pass", "", 'single', - PyCF_DONT_IMPLY_DEDENT)) + self.assertEqual(compile_command(""), + compile("pass", "", 'single', + PyCF_DONT_IMPLY_DEDENT)) + self.assertEqual(compile_command("\n"), + compile("pass", "", 'single', + PyCF_DONT_IMPLY_DEDENT)) else: av("") av("\n") @@ -109,7 +109,6 @@ av("#a\n#b\na**3","eval") av("\n\na = 1\n\n") - av("\n\nif 1: a=1\n\n") av("if 1:\n pass\n if 1:\n pass\n else:\n pass\n") @@ -119,9 +118,7 @@ av("\n \na**3","eval") av("#a\n#b\na**3","eval") - # this failed under Jython 2.2.1 av("def f():\n try: pass\n finally: [x for x in (1,2)]\n") - av("def f():\n pass\n#foo\n") #XXX: works in CPython @@ -169,8 +166,6 @@ ai("9+ \\","eval") ai("lambda z: \\","eval") - #Did not work in Jython 2.5rc2 see first issue in - # http://bugs.jython.org/issue1354 ai("if True:\n if True:\n if True: \n") ai("@a(") @@ -303,22 +298,17 @@ ai("del (1,)") ai("del [1]") ai("del '1'") + ai("[i for i in range(10)] = (1, 2, 3)") - ai("a = 1 and b = 2"); # Merge test cases below upstream. ai("def x():\n pass\na=1\n") def test_filename(self): - self.assertEquals(compile_command("a = 1\n", "abc").co_filename, - compile("a = 1\n", "abc", 'single').co_filename) - self.assertNotEquals(compile_command("a = 1\n", "abc").co_filename, - compile("a = 1\n", "def", 'single').co_filename) - - def test_no_universal_newlines(self): - # previously \r was translated due to universal newlines - code = compile_command("'\rfoo\r'", symbol='eval') - self.assertEqual(eval(code), '\rfoo\r') + self.assertEqual(compile_command("a = 1\n", "abc").co_filename, + compile("a = 1\n", "abc", 'single').co_filename) + self.assertNotEqual(compile_command("a = 1\n", "abc").co_filename, + compile("a = 1\n", "def", 'single').co_filename) def test_main(): -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 21 18:38:27 2015 From: jython-checkins at python.org (santoso.wijaya) Date: Wed, 21 Jan 2015 17:38:27 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_issue_=232081_where_wri?= =?utf-8?q?te-only_file_cannot_be_opened_for_write=2E?= Message-ID: <20150121173739.103307.78411@psf.io> https://hg.python.org/jython/rev/62f6e0189460 changeset: 7555:62f6e0189460 user: Santoso Wijaya date: Tue Jan 20 22:48:28 2015 -0800 summary: Fix issue #2081 where write-only file cannot be opened for write. files: Lib/test/test_file_jy.py | 8 ++++++++ src/org/python/core/io/FileIO.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_file_jy.py b/Lib/test/test_file_jy.py --- a/Lib/test/test_file_jy.py +++ b/Lib/test/test_file_jy.py @@ -43,6 +43,14 @@ else: self.assertTrue(False) + @unittest.skipUnless(hasattr(os, 'chmod'), 'chmod() support required for this test') + def test_issue2081(self): + f = open(test_support.TESTFN, 'wb') + f.close() + os.chmod(test_support.TESTFN, 200) # write-only + f = open(test_support.TESTFN, 'w') # should succeed, raised IOError (permission denied) prior to fix + f.close() + def test_main(): test_support.run_unittest(FileTestCase) diff --git a/src/org/python/core/io/FileIO.java b/src/org/python/core/io/FileIO.java --- a/src/org/python/core/io/FileIO.java +++ b/src/org/python/core/io/FileIO.java @@ -72,7 +72,7 @@ File absPath = new RelativeFile(name.toString()); try { - if (appending && !(reading || plus)) { + if ((appending && !(reading || plus)) || (writing && !reading && !plus)) { // Take advantage of FileOutputStream's append mode fromFileOutputStream(absPath); } else { @@ -181,7 +181,7 @@ * @param absPath The absolute path File to open */ private void fromFileOutputStream(File absPath) throws FileNotFoundException { - fileOutputStream = new FileOutputStream(absPath, true); + fileOutputStream = new FileOutputStream(absPath, appending); fileChannel = fileOutputStream.getChannel(); } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Jan 23 05:31:16 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 23 Jan 2015 04:31:16 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Improved_locale_support=2C_?= =?utf-8?q?especially_for_Turkish?= Message-ID: <20150123043113.87111.6225@psf.io> https://hg.python.org/jython/rev/5c60689c2819 changeset: 7556:5c60689c2819 user: Jim Baker date: Thu Jan 22 21:31:05 2015 -0700 summary: Improved locale support, especially for Turkish Fixes http://bugs.jython.org/issue1874 and http://bugs.jython.org/issue2261. See also http://bugs.python.org/issue17252#msg182519 for CPython 3; for unicode strings, Jython follows Java's correct support for Turkish lowercasing and uppercasing of u'i'/u'I' in a Turkish locale (CPython 3 does not have yet locale aware Unicode support). files: Lib/test/test_os_jy.py | 69 ++++++++++++++- src/org/python/core/PyString.java | 5 +- src/org/python/core/PyUnicode.java | 4 +- src/org/python/modules/posix/OS.java | 3 +- src/org/python/modules/time/Time.java | 2 +- 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_os_jy.py b/Lib/test/test_os_jy.py --- a/Lib/test/test_os_jy.py +++ b/Lib/test/test_os_jy.py @@ -128,7 +128,7 @@ # lacks buffer api: self.assertRaises(TypeError, self.do_write, 1.5, 4) -class OSUnicodeTestCase(unittest.TestCase): +class UnicodeTestCase(unittest.TestCase): def test_env(self): with test_support.temp_cwd(name=u"tempcwd-??"): @@ -191,6 +191,70 @@ self.assertTrue(f.exists(), "File %r (%r) should be testable for existence" % ( f, entry_path)) +class LocaleTestCase(unittest.TestCase): + + def get_installed_locales(self, codes, msg=None): + def normalize(code): + # OS X and Ubuntu (at the very least) differ slightly in locale code formatting + return code.strip().replace("-", "").lower() + + try: + installed_codes = dict(((normalize(code), code) for + code in subprocess.check_output(["locale", "-a"]).split())) + except subprocess.CalledProcessError: + unittest.skip("locale command not available, cannot test") + + if msg is None: + msg = "One of %s tested locales is not installed" % (codes,) + available_codes = [] + for code in codes: + if normalize(code) in installed_codes: + available_codes.append(installed_codes[normalize(code)]) + unittest.skipUnless(available_codes, msg) + return available_codes + + # must be on posix and turkish locale supported + def test_turkish_locale_posix_module(self): + # Verifies fix of http://bugs.jython.org/issue1874 + self.get_installed_locales(["tr_TR.UTF-8"], "Turkish locale not installed, cannot test") + newenv = os.environ.copy() + newenv["LC_ALL"] = "tr_TR.UTF-8" # set to Turkish locale + self.assertEqual( + subprocess.check_output( + [sys.executable, "-c", + "import sys; assert 'posix' in sys.builtin_module_names"], + env=newenv), + "") + + def test_turkish_locale_string_lower_upper(self): + # Verifies fix of http://bugs.jython.org/issue1874 + self.get_installed_locales(["tr_TR.UTF-8"], "Turkish locale not installed, cannot test") + newenv = os.environ.copy() + newenv["LC_ALL"] = "tr_TR.UTF-8" # set to Turkish locale + self.assertEqual( + subprocess.check_output( + [sys.executable, "-c", + 'print repr(["I".lower(), u"I".lower(), "i".upper(), u"i".upper()])'], + env=newenv), + # Should not convert str for 'i'/'I', but should convert + # unicode if in Turkish locale; this behavior intentionally is + # different than CPython; see also http://bugs.python.org/issue17252 + "['i', u'\\u0131', 'I', u'\\u0130']\n") + + def test_strptime_locale(self): + # Verifies fix of http://bugs.jython.org/issue2261 + newenv = os.environ.copy() + codes = [ + "cs_CZ.UTF-8", "pl_PL.UTF-8", "ru_RU.UTF-8", + "sk_SK.UTF-8", "uk_UA.UTF-8", "zh_CN.UTF-8"] + for code in self.get_installed_locales(codes): + newenv["LC_ALL"] = code + self.assertEqual( + subprocess.check_output( + [sys.executable, "-c", + 'import datetime; print(datetime.datetime.strptime("2015-01-22", "%Y-%m-%d"))'], + env=newenv), + "2015-01-22 00:00:00\n") def test_main(): @@ -199,7 +263,8 @@ OSDirTestCase, OSStatTestCase, OSWriteTestCase, - OSUnicodeTestCase + UnicodeTestCase, + LocaleTestCase, ) if __name__ == '__main__': diff --git a/src/org/python/core/PyString.java b/src/org/python/core/PyString.java --- a/src/org/python/core/PyString.java +++ b/src/org/python/core/PyString.java @@ -9,6 +9,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.List; +import java.util.Locale; import org.python.core.buffer.BaseBuffer; import org.python.core.buffer.SimpleStringBuffer; @@ -1048,7 +1049,7 @@ @ExposedMethod(doc = BuiltinDocs.str_lower_doc) final String str_lower() { - return getString().toLowerCase(); + return getString().toLowerCase(Locale.ENGLISH); } public String upper() { @@ -1057,7 +1058,7 @@ @ExposedMethod(doc = BuiltinDocs.str_upper_doc) final String str_upper() { - return getString().toUpperCase(); + return getString().toUpperCase(Locale.ENGLISH); } public String title() { diff --git a/src/org/python/core/PyUnicode.java b/src/org/python/core/PyUnicode.java --- a/src/org/python/core/PyUnicode.java +++ b/src/org/python/core/PyUnicode.java @@ -936,12 +936,12 @@ @ExposedMethod(doc = BuiltinDocs.unicode_lower_doc) final PyObject unicode_lower() { - return new PyUnicode(str_lower()); + return new PyUnicode(getString().toLowerCase()); } @ExposedMethod(doc = BuiltinDocs.unicode_upper_doc) final PyObject unicode_upper() { - return new PyUnicode(str_upper()); + return new PyUnicode(getString().toUpperCase()); } @ExposedMethod(doc = BuiltinDocs.unicode_title_doc) diff --git a/src/org/python/modules/posix/OS.java b/src/org/python/modules/posix/OS.java --- a/src/org/python/modules/posix/OS.java +++ b/src/org/python/modules/posix/OS.java @@ -1,6 +1,7 @@ /* Copyright (c) Jython Developers */ package org.python.modules.posix; +import java.util.Locale; import org.python.core.PySystemState; /** @@ -32,7 +33,7 @@ } String getModuleName() { - return name().toLowerCase(); + return name().toLowerCase(Locale.ENGLISH); } String[][] getShellCommands() { diff --git a/src/org/python/modules/time/Time.java b/src/org/python/modules/time/Time.java --- a/src/org/python/modules/time/Time.java +++ b/src/org/python/modules/time/Time.java @@ -678,7 +678,7 @@ // os.environ) // // TODO: Check how CPython deals with this problem. - return new PyString(s); + return Py.newStringOrUnicode(s); } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Jan 23 23:31:21 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 23 Jan 2015 22:31:21 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_Popen=2Ekill_on_Posix_a?= =?utf-8?q?nd_Popen=2Esend=5Fsignal_in_general?= Message-ID: <20150123223118.75786.77373@psf.io> https://hg.python.org/jython/rev/8e8c19c827fd changeset: 7557:8e8c19c827fd user: Pekka Kl?rck date: Fri Jan 23 15:31:02 2015 -0700 summary: Fix Popen.kill on Posix and Popen.send_signal in general Merged from https://github.com/jythontools/jython/pull/14 Fixes http://bugs.jython.org/issue2219 and http://bugs.jython.org/issue2220 files: Lib/subprocess.py | 38 +++++++++---- Lib/test/test_subprocess_jy.py | 59 ++++++++++++++++++++++ 2 files changed, 84 insertions(+), 13 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1425,24 +1425,36 @@ self._stdin_thread.interrupt() return self.returncode - def send_signal(self, sig): - """Send a signal to the process - """ - if sig == signal.SIGTERM: - self.terminate() - elif sig == signal.CTRL_C_EVENT: - os.kill(self.pid, signal.CTRL_C_EVENT) - elif sig == signal.CTRL_BREAK_EVENT: - os.kill(self.pid, signal.CTRL_BREAK_EVENT) - else: - raise ValueError("Unsupported signal: {}".format(sig)) - def terminate(self): """Terminates the process """ self._process.destroy() - kill = terminate + if os._name not in _win_oses: + + def kill(self): + if hasattr(self._process, 'destroyForcibly'): + self._process.destroyForcibly() + else: + self.send_signal(signal.SIGKILL) + + def send_signal(self, sig): + """Send a signal to the process + """ + os.kill(self.pid, sig) + + else: + + kill = terminate + + def send_signal(self, sig): + """Send a signal to the process + """ + if sig == signal.SIGTERM: + self.terminate() + else: + raise ValueError("Unsupported signal: {}".format(sig)) + else: # diff --git a/Lib/test/test_subprocess_jy.py b/Lib/test/test_subprocess_jy.py --- a/Lib/test/test_subprocess_jy.py +++ b/Lib/test/test_subprocess_jy.py @@ -2,10 +2,68 @@ import unittest import os import sys +import signal +import time from test import test_support from subprocess import PIPE, Popen, _cmdline2list +class TerminationAndSignalTest(unittest.TestCase): + + def setUp(self): + program = ''' +import signal, sys + +def print_signal(signum, frame): + print signum + +def exit_signal(signum, frame): + sys.exit(signum) + +signal.signal(signal.SIGTERM, print_signal) +signal.signal(signal.SIGINT, exit_signal) + +print 'Started' +sys.stdout.flush() + +while True: + pass +''' + self.proc = Popen(['python', '-c', program], stdout=PIPE, stderr=PIPE) + assert self.proc.stdout.readline().strip() == 'Started' + + def tearDown(self): + if self.proc.poll() is None: + self.proc.kill() + + def test_kill(self): + self.proc.kill() + self.assertNotEqual(self.proc.wait(), 0) + + if os._name != 'nt': + + def test_terminate_can_be_ignored_on_posix(self): + self.proc.terminate() + self.assertIsNone(self.proc.poll()) + + def test_send_signals_on_posix(self): + self.proc.send_signal(signal.SIGTERM) + time.sleep(0.01) # Make sure SIGTERM is handled first + self.proc.send_signal(signal.SIGINT) + self.assertEqual(self.proc.wait(), 2) + self.assertEqual(self.proc.stdout.read(), '15\n') + + else: + + def test_terminate_cannot_be_ignored_on_windows(self): + self.proc.terminate() + self.assertNotEqual(self.proc.wait(), 0) + + def test_sending_sigterm_signal_terminates_on_windows(self): + self.proc.send_signal(signal.SIGTERM) + self.assertNotEqual(self.proc.wait(), 0) + + class PidTest(unittest.TestCase): def testPid(self): @@ -87,6 +145,7 @@ def test_main(): test_support.run_unittest( + TerminationAndSignalTest, PidTest, EnvironmentInheritanceTest, JythonOptsTest, -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Jan 24 01:02:40 2015 From: jython-checkins at python.org (jim.baker) Date: Sat, 24 Jan 2015 00:02:40 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_NEWS?= Message-ID: <20150124000233.87135.20328@psf.io> https://hg.python.org/jython/rev/ef585365ab7f changeset: 7558:ef585365ab7f user: Jim Baker date: Fri Jan 23 17:02:28 2015 -0700 summary: Update NEWS files: NEWS | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -74,6 +74,14 @@ NotImplementedError, instead of returning None (in Java, null) or some "zero", if they are not implemented in the extending Python class. + - os.getenv, os.listdir, sys.argv now return unicode instead of + str values if a given value is not ascii, thus allowing such + values to be passed through to Java, eg + java.io.File(sys.argv[1]). Earlier such behavior was potentially + silently failing in Python functions, but passing through to + Java because of bug 2037. This behavior conforms with Python + 3.x, which uses Unicode. + Jython 2.7b3 Bugs Fixed - [ 2225 ] Jython+django-jython - no module named site -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 28 03:51:15 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 28 Jan 2015 02:51:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Do_not_clobber_main_thread_?= =?utf-8?q?name_if_set_by_user?= Message-ID: <20150128025113.39296.86568@psf.io> https://hg.python.org/jython/rev/c512d451b76e changeset: 7560:c512d451b76e user: Jim Baker date: Tue Jan 27 19:41:13 2015 -0700 summary: Do not clobber main thread name if set by user files: Lib/threading.py | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -274,7 +274,13 @@ class _MainThread(Thread): def __init__(self): - Thread.__init__(self, name="MainThread") + if java.lang.Thread.currentThread().name == "main": + # Do not clobber the thread name if the user set it to + # something different + kw = dict(name="MainThread") + else: + kw = {} + Thread.__init__(self, **kw) import atexit atexit.register(self.__exitfunc) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 28 03:51:15 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 28 Jan 2015 02:51:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_crypt_module=2C_using_J?= =?utf-8?q?NR_Posix?= Message-ID: <20150128025113.34410.25081@psf.io> https://hg.python.org/jython/rev/8641d74f3575 changeset: 7559:8641d74f3575 user: Jim Baker date: Tue Jan 27 19:39:41 2015 -0700 summary: Add crypt module, using JNR Posix files: Lib/crypt.py | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/crypt.py b/Lib/crypt.py new file mode 100644 --- /dev/null +++ b/Lib/crypt.py @@ -0,0 +1,10 @@ +from jnr.posix import POSIXFactory +from org.python.modules.posix import PythonPOSIXHandler + + +__all__ = ["crypt"] +_posix = POSIXFactory.getPOSIX(PythonPOSIXHandler(), True) + + +def crypt(word, salt): + return _posix.crypt(word, salt) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 28 03:51:15 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 28 Jan 2015 02:51:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Adds_various_os=2E*_functio?= =?utf-8?q?ns=3B_supports_int_file_descriptors?= Message-ID: <20150128025114.39296.39334@psf.io> https://hg.python.org/jython/rev/e1a246f6a178 changeset: 7561:e1a246f6a178 user: Jim Baker date: Tue Jan 27 19:51:07 2015 -0700 summary: Adds various os.* functions; supports int file descriptors Adds os.* functions for file descriptors, including os.fstat, as well as support int file descriptors from underlying OS. Also adds os.times. Uses more of the Posix support now provided by Java Native Runtime Posix 3.0.x. Fixes http://bugs.jython.org/issue1560, http://bugs.jython.org/issue1736, and http://bugs.jython.org/issue1948 files: Lib/test/test_fileno.py | 2 +- Lib/test/test_os.py | 12 +- src/org/python/core/PyObject.java | 9 + src/org/python/core/io/FileIO.java | 37 + src/org/python/modules/posix/PosixModule.java | 305 ++++++++-- 5 files changed, 294 insertions(+), 71 deletions(-) diff --git a/Lib/test/test_fileno.py b/Lib/test/test_fileno.py --- a/Lib/test/test_fileno.py +++ b/Lib/test/test_fileno.py @@ -32,7 +32,7 @@ self.assertEqual(os.path.getsize(self.filename), 0) self.fp.close() - raises(IOError, 9, os.ftruncate, self.fd, 0) + raises(OSError, 9, os.ftruncate, self.fd, 0) def test_lseek(self): self.assertEqual(os.lseek(self.fd, 0, 1), 0) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -32,8 +32,6 @@ os.close(f) self.assertTrue(os.access(test_support.TESTFN, os.W_OK)) - @unittest.skipIf(test_support.is_jython, - "Jython does not yet support os.dup.") def test_closerange(self): first = os.open(test_support.TESTFN, os.O_CREAT|os.O_RDWR) # We must allocate two consecutive file descriptors, otherwise @@ -371,8 +369,6 @@ class WalkTests(unittest.TestCase): """Tests for os.walk().""" - @unittest.skipIf(test_support.is_jython, - "FIXME: investigate in Jython") def test_traversal(self): import os from os.path import join @@ -578,7 +574,8 @@ def check(self, f, *args): try: - f(test_support.make_bad_fd(), *args) + fd = test_support.make_bad_fd() + f(fd, *args) except OSError as e: self.assertEqual(e.errno, errno.EBADF) except ValueError: @@ -587,14 +584,13 @@ self.fail("%r didn't raise a OSError with a bad file descriptor" % f) - @unittest.skipIf(test_support.is_jython, "FIXME: investigate for Jython") def test_isatty(self): if hasattr(os, "isatty"): self.assertEqual(os.isatty(test_support.make_bad_fd()), False) def test_closerange(self): if hasattr(os, "closerange"): - fd = test_support.make_bad_fd() + fd = int(test_support.make_bad_fd()) # need to take an int for Jython, given this test # Make sure none of the descriptors we are about to close are # currently valid (issue 6542). for i in range(10): @@ -624,8 +620,6 @@ if hasattr(os, "fpathconf"): self.check(os.fpathconf, "PC_NAME_MAX") - @unittest.skipIf(test_support.is_jython, - "ftruncate not implemented in Jython") def test_ftruncate(self): if hasattr(os, "ftruncate"): self.check(os.ftruncate, 0) diff --git a/src/org/python/core/PyObject.java b/src/org/python/core/PyObject.java --- a/src/org/python/core/PyObject.java +++ b/src/org/python/core/PyObject.java @@ -590,6 +590,15 @@ } /** + * Determine if this object can act as an int (implements __int__). + * + * @return true if the object can act as an int + */ + public boolean isInteger() { + return getType().lookup("__int__") != null; + } + + /** * Determine if this object can act as an index (implements __index__). * * @return true if the object can act as an index diff --git a/src/org/python/core/io/FileIO.java b/src/org/python/core/io/FileIO.java --- a/src/org/python/core/io/FileIO.java +++ b/src/org/python/core/io/FileIO.java @@ -2,19 +2,23 @@ package org.python.core.io; import java.io.File; +import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; +import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import jnr.constants.platform.Errno; +import jnr.posix.util.FieldAccess; import jnr.posix.util.Platform; import org.python.core.Py; +import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.util.RelativeFile; import org.python.modules.posix.PosixModule; @@ -435,4 +439,37 @@ public FileChannel getChannel() { return fileChannel; } + + public FileDescriptor getFD() { + if (file != null) { + try { + return file.getFD(); + } catch (IOException ioe) { + throw Py.OSError(ioe); + } + } else if (fileOutputStream != null) { + try { + return fileOutputStream.getFD(); + } catch (IOException ioe) { + throw Py.OSError(ioe); + } + } + throw Py.OSError(Errno.EBADF); + } + + public PyObject __int__() { + int intFD = -1; + try { + Field fdField = FieldAccess.getProtectedField(FileDescriptor.class, "fd"); + intFD = fdField.getInt(getFD()); + } catch (SecurityException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + return Py.newInteger(intFD); + } + + public PyObject __add__(PyObject otherObj) { + return __int__().__add__(otherObj); + } } diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java --- a/src/org/python/modules/posix/PosixModule.java +++ b/src/org/python/modules/posix/PosixModule.java @@ -6,10 +6,13 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; @@ -19,9 +22,12 @@ import jnr.constants.Constant; import jnr.constants.platform.Errno; +import jnr.constants.platform.Sysconf; import jnr.posix.FileStat; import jnr.posix.POSIX; import jnr.posix.POSIXFactory; +import jnr.posix.Times; +import jnr.posix.util.FieldAccess; import jnr.posix.util.Platform; import org.python.core.BufferProtocol; @@ -34,14 +40,11 @@ import org.python.core.PyException; import org.python.core.PyFile; import org.python.core.PyFloat; -import org.python.core.PyInteger; import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PySystemState; import org.python.core.PyTuple; import org.python.core.imp; -import org.python.core.io.FileDescriptors; import org.python.core.io.FileIO; import org.python.core.io.IOBase; import org.python.core.io.RawIOBase; @@ -114,7 +117,8 @@ dict.__setitem__("error", Py.OSError); dict.__setitem__("stat_result", PyStatResult.TYPE); - // Faster call paths + // Faster call paths, because __call__ is defined + dict.__setitem__("fstat", new FstatFunction()); dict.__setitem__("lstat", new LstatFunction()); dict.__setitem__("stat", new StatFunction()); @@ -141,6 +145,81 @@ dict.__setitem__("__doc__", __doc__); } + // Combine Java FileDescriptor objects with + // Posix int file descriptors in one representation + private static class FDUnion { + volatile int intFD; + final FileDescriptor javaFD; + + FDUnion(int fd) { + intFD = fd; + javaFD = null; + } + FDUnion(FileDescriptor fd) { + intFD = -1; + javaFD = fd; + } + + boolean isIntFD() { + return intFD != -1; + } + + // FIXME should this store this int fd -> FileDescriptor in a weak value map so it can be looked up later? + int getIntFD() { + return getIntFD(true); + } + + int getIntFD(boolean checkFD) { + if (intFD == -1) { + if (!(javaFD instanceof FileDescriptor)) { + throw Py.OSError(Errno.EBADF); + } + try { + Field fdField = FieldAccess.getProtectedField(FileDescriptor.class, "fd"); + intFD = fdField.getInt(javaFD); + } catch (SecurityException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + } + if (checkFD) { + posix.fstat(intFD); // check if this a good FD or not + } + return intFD; + } + + @Override + public String toString() { + return "FDUnion(int=" + intFD + ", java=" + javaFD + ")"; + } + + } + + private static FDUnion getFD(PyObject fdObj) { + if (fdObj.isInteger()) { + int intFd = fdObj.asInt(); + switch (intFd) { + case 0: + return new FDUnion(FileDescriptor.in); + case 1: + return new FDUnion(FileDescriptor.out); + case 2: + return new FDUnion(FileDescriptor.err); + default: + return new FDUnion(intFd); + } + } + Object tojava = fdObj.__tojava__(FileDescriptor.class); + if (tojava != Py.NoConversion) { + return new FDUnion((FileDescriptor) tojava); + } + tojava = fdObj.__tojava__(FileIO.class); + if (tojava != Py.NoConversion) { + return new FDUnion(((FileIO)tojava).getFD()); + } + throw Py.TypeError("an integer or Java/Jython file descriptor is required"); + } + public static PyString __doc___exit = new PyString( "_exit(status)\n\n" + "Exit to the system with specified status, without normal exit processing."); @@ -226,13 +305,32 @@ "close(fd)\n\n" + "Close a file descriptor (for low level IO)."); public static void close(PyObject fd) { - try { - FileDescriptors.get(fd).close(); - } catch (PyException pye) { - throw badFD(); + Object obj = fd.__tojava__(RawIOBase.class); + if (obj != Py.NoConversion) { + ((RawIOBase)obj).close(); + } else { + posix.close(getFD(fd).getIntFD()); } } + public static void closerange(PyObject fd_lowObj, PyObject fd_highObj) { + int fd_low = getFD(fd_lowObj).getIntFD(false); + int fd_high = getFD(fd_highObj).getIntFD(false); + for (int i = fd_low; i < fd_high; i++) { + try { + posix.close(i); // FIXME catch exceptions + } catch (Exception e) {} + } + } + + public static PyObject dup(PyObject fd1) { + return Py.newInteger(posix.dup(getFD(fd1).getIntFD())); + } + + public static PyObject dup2(PyObject fd1, PyObject fd2) { + return Py.newInteger(posix.dup2(getFD(fd1).getIntFD(), getFD(fd2).getIntFD())); + } + public static PyString __doc__fdopen = new PyString( "fdopen(fd [, mode='r' [, bufsize]]) -> file_object\n\n" + "Return an open file object connected to a file descriptor."); @@ -249,7 +347,12 @@ if (mode.length() == 0 || !"rwa".contains("" + mode.charAt(0))) { throw Py.ValueError(String.format("invalid file mode '%s'", mode)); } - RawIOBase rawIO = FileDescriptors.get(fd); + Object javaobj = fd.__tojava__(RawIOBase.class); + if (javaobj == Py.NoConversion) { + getFD(fd).getIntFD(); + throw Py.NotImplementedError("Integer file descriptors not currently supported for fdopen"); + } + RawIOBase rawIO = (RawIOBase)javaobj; if (rawIO.closed()) { throw badFD(); } @@ -270,21 +373,30 @@ "does not force update of metadata."); @Hide(OS.NT) public static void fdatasync(PyObject fd) { - fsync(fd, false); + Object javaobj = fd.__tojava__(RawIOBase.class); + if (javaobj != Py.NoConversion) { + fsync((RawIOBase)javaobj, false); + } else { + posix.fdatasync(getFD(fd).getIntFD()); + } } public static PyString __doc__fsync = new PyString( "fsync(fildes)\n\n" + "force write of file with filedescriptor to disk."); public static void fsync(PyObject fd) { - fsync(fd, true); + Object javaobj = fd.__tojava__(RawIOBase.class); + if (javaobj != Py.NoConversion) { + fsync((RawIOBase)javaobj, true); + } else { + posix.fsync(getFD(fd).getIntFD()); + } } /** * Internal fsync implementation. */ - private static void fsync(PyObject fd, boolean metadata) { - RawIOBase rawIO = FileDescriptors.get(fd); + private static void fsync(RawIOBase rawIO, boolean metadata) { rawIO.checkClosed(); Channel channel = rawIO.getChannel(); if (!(channel instanceof FileChannel)) { @@ -304,11 +416,17 @@ public static PyString __doc__ftruncate = new PyString( "ftruncate(fd, length)\n\n" + "Truncate a file to a specified length."); + public static void ftruncate(PyObject fd, long length) { - try { - FileDescriptors.get(fd).truncate(length); - } catch (PyException pye) { - throw Py.IOError(Errno.EBADF); + Object javaobj = fd.__tojava__(RawIOBase.class); + if (javaobj != Py.NoConversion) { + try { + ((RawIOBase) javaobj).truncate(length); + } catch (PyException pye) { + throw Py.OSError(Errno.EBADF); + } + } else { + posix.ftruncate(getFD(fd).getIntFD(), length); } } @@ -390,40 +508,40 @@ return posix.getpgrp(); } + + public static PyString __doc__isatty = new PyString( "isatty(fd) -> bool\n\n" + "Return True if the file descriptor 'fd' is an open file descriptor\n" + "connected to the slave end of a terminal."); public static boolean isatty(PyObject fdObj) { - if (fdObj instanceof PyInteger) { - FileDescriptor fd; - switch (fdObj.asInt()) { - case 0: - fd = FileDescriptor.in; - break; - case 1: - fd = FileDescriptor.out; - break; - case 2: - fd = FileDescriptor.err; - break; - default: - throw Py.NotImplementedError("Integer file descriptor compatibility only " - + "available for stdin, stdout and stderr (0-2)"); + Object tojava = fdObj.__tojava__(IOBase.class); + if (tojava != Py.NoConversion) { + try { + return ((IOBase) tojava).isatty(); + } catch (PyException pye) { + if (pye.match(Py.ValueError)) { + return false; + } + throw pye; } - return posix.isatty(fd); } - Object tojava = fdObj.__tojava__(FileDescriptor.class); - if (tojava != Py.NoConversion) { - return posix.isatty((FileDescriptor)tojava); + FDUnion fd = getFD(fdObj); + if (fd.javaFD != null) { + return posix.isatty(fd.javaFD); } - - tojava = fdObj.__tojava__(IOBase.class); - if (tojava == Py.NoConversion) { - throw Py.TypeError("a file descriptor is required"); + try { + fd.getIntFD(); // evaluate for side effect of checking EBADF or raising TypeError + } catch (PyException pye) { + if (pye.match(Py.OSError)) { + return false; + } + throw pye; } - return ((IOBase)tojava).isatty(); + throw Py.NotImplementedError( + "Integer file descriptor compatibility only " + + "available for stdin, stdout and stderr (0-2)"); } public static PyString __doc__kill = new PyString( @@ -504,10 +622,15 @@ "lseek(fd, pos, how) -> newpos\n\n" + "Set the current position of a file descriptor."); public static long lseek(PyObject fd, long pos, int how) { - try { - return FileDescriptors.get(fd).seek(pos, how); - } catch (PyException pye) { - throw badFD(); + Object javaobj = fd.__tojava__(RawIOBase.class); + if (javaobj != Py.NoConversion) { + try { + return ((RawIOBase) javaobj).seek(pos, how); + } catch (PyException pye) { + throw badFD(); + } + } else { + return posix.lseek(getFD(fd).getIntFD(), pos, how); } } @@ -610,10 +733,17 @@ "read(fd, buffersize) -> string\n\n" + "Read a file descriptor."); public static PyObject read(PyObject fd, int buffersize) { - try { - return new PyString(StringUtil.fromBytes(FileDescriptors.get(fd).read(buffersize))); - } catch (PyException pye) { - throw badFD(); + Object javaobj = fd.__tojava__(RawIOBase.class); + if (javaobj != Py.NoConversion) { + try { + return new PyString(StringUtil.fromBytes(((RawIOBase) javaobj).read(buffersize))); + } catch (PyException pye) { + throw badFD(); + } + } else { + ByteBuffer buffer = ByteBuffer.allocate(buffersize); + posix.read(getFD(fd).getIntFD(), buffer, buffersize); + return new PyString(StringUtil.fromBytes(buffer)); } } @@ -709,6 +839,26 @@ } } + private static PyFloat ratio(long num, long div) { + return Py.newFloat(((double)num)/((double)div)); + } + + public static PyString __doc__times = new PyString( + "times() -> (utime, stime, cutime, cstime, elapsed_time)\n\n" + + "Return a tuple of floating point numbers indicating process times."); + + public static PyTuple times() { + Times times = posix.times(); + long CLK_TCK = Sysconf._SC_CLK_TCK.longValue(); + return new PyTuple( + ratio(times.utime(), CLK_TCK), + ratio(times.stime(), CLK_TCK), + ratio(times.cutime(), CLK_TCK), + ratio(times.cstime(), CLK_TCK), + ratio(ManagementFactory.getRuntimeMXBean().getUptime(), 1000) + ); + } + public static PyString __doc__umask = new PyString( "umask(new_mask) -> old_mask\n\n" + "Set the current numeric umask and return the previous umask."); @@ -810,18 +960,23 @@ return new PyTuple(Py.newInteger(pid), Py.newInteger(status[0])); } - public static PyString __doc__write = new PyString("write(fd, string) -> byteswritten\n\n" - + "Write a string to a file descriptor."); + public static PyString __doc__write = new PyString( + "write(fd, string) -> byteswritten\n\n" + + "Write a string to a file descriptor."); public static int write(PyObject fd, BufferProtocol bytes) { // Get a buffer view: we can cope with N-dimensional data, but not strided data. try (PyBuffer buf = bytes.getBuffer(PyBUF.ND)) { // Get a ByteBuffer of that data, setting the position and limit to the real data. - ByteBuffer bb = buf.getNIOByteBuffer(); - try { - // Write the data (returning the count of bytes). - return FileDescriptors.get(fd).write(bb); - } catch (PyException pye) { - throw badFD(); + ByteBuffer bb = buf.getNIOByteBuffer(); + Object javaobj = fd.__tojava__(RawIOBase.class); + if (javaobj != Py.NoConversion) { + try { + return ((RawIOBase) javaobj).write(bb); + } catch (PyException pye) { + throw badFD(); + } + } else { + return posix.write(getFD(fd).getIntFD(), bb, bb.position()); } } } @@ -907,11 +1062,21 @@ /** * Return the absolute form of path. * - * @param path a PyObject, raising a TypeError if an invalid path type + * @param pathObj a PyObject, raising a TypeError if an invalid path type * @return an absolute path String */ - private static String absolutePath(PyObject path) { - return PySystemState.getPathLazy(asPath(path)); + private static String absolutePath(PyObject pathObj) { + String pathStr = asPath(pathObj); + if (pathStr.equals("")) { + // Otherwise this path will get prefixed with the current working directory, + // which is both wrong and very surprising! + throw Py.OSError(Errno.ENOENT, pathObj); + } + Path path = FileSystems.getDefault().getPath(pathStr); + if (!path.isAbsolute()) { + path = FileSystems.getDefault().getPath(Py.getSystemState().getCurrentWorkingDir(), pathStr); + } + return path.toAbsolutePath().normalize().toString(); } private static PyException badFD() { @@ -967,7 +1132,6 @@ @Override public PyObject __call__(PyObject path) { String absolutePath = absolutePath(path); - // round tripping from a string to a file to a string loses // trailing slashes so add them back back in to get correct posix.stat // behaviour if path is not a directory. @@ -977,4 +1141,23 @@ return PyStatResult.fromFileStat(posix.stat(absolutePath)); } } + + static class FstatFunction extends PyBuiltinFunctionNarrow { + FstatFunction() { + super("fstat", 1, 1, + "fstat(fd) -> stat result\\n\\nLike stat(), but for an open file descriptor."); + } + + @Override + public PyObject __call__(PyObject fdObj) { + FDUnion fd = getFD(fdObj); + FileStat stat; + if (fd.isIntFD()) { + stat = posix.fstat(fd.intFD); + } else { + stat = posix.fstat(fd.javaFD);; + } + return PyStatResult.fromFileStat(stat); + } + } } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Jan 28 06:45:26 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 28 Jan 2015 05:45:26 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Make_regrtest_more_robust_f?= =?utf-8?q?or_Windows?= Message-ID: <20150128054518.39268.77151@psf.io> https://hg.python.org/jython/rev/6f12314e79c9 changeset: 7562:6f12314e79c9 user: Jim Baker date: Tue Jan 27 22:45:13 2015 -0700 summary: Make regrtest more robust for Windows Added workarounds for the problem that Windows has in deleting files: unlike unlink on Posix, Windows cannot delete a file if a process still holds it. This problem is magnified because of the use of a background process for Java on Windows, so removing dangling test_support.TESTFN files generally require system reboot or usage of tools like Process Explorer to kill the holding process (https://technet.microsoft.com/en-us/sysinternals/bb896653.aspx) files: Lib/test/regrtest.py | 4 + Lib/test/test_os.py | 3 + Lib/test/test_support.py | 2 +- Lib/test/test_tarfile.py | 1660 ++++++++++++++++++++++++++ 4 files changed, 1668 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -677,6 +677,10 @@ if not os.path.exists(name): continue + # work around tests depending on refcounting files, + # but this doesn't work with respect to Windows + test_support.gc_collect() + if os.path.isdir(name): kind, nuker = "directory", shutil.rmtree elif os.path.isfile(name): diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -23,6 +23,7 @@ # Tests creating TESTFN class FileTests(unittest.TestCase): def setUp(self): + test_support.gc_collect() if os.path.exists(test_support.TESTFN): os.unlink(test_support.TESTFN) tearDown = setUp @@ -32,6 +33,8 @@ os.close(f) self.assertTrue(os.access(test_support.TESTFN, os.W_OK)) + @unittest.skipIf(test_support.is_jython and os._name == "nt", + "Does not properly close files under Windows") def test_closerange(self): first = os.open(test_support.TESTFN, os.O_CREAT|os.O_RDWR) # We must allocate two consecutive file descriptors, otherwise diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -189,7 +189,7 @@ except KeyError: pass -if sys.platform.startswith("win"): +if sys.platform.startswith("win") or os.name == "java" and os._name == "nt": def _waitfor(func, pathname, waitall=False): # Peform the operation func(pathname) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_tarfile.py @@ -0,0 +1,1660 @@ +# -*- coding: iso-8859-15 -*- + +import sys +import os +import shutil +import StringIO +from hashlib import md5 +import errno + +import unittest +import tarfile + +from test import test_support + +# Check for our compression modules. +try: + import gzip + gzip.GzipFile +except (ImportError, AttributeError): + gzip = None +try: + import bz2 +except ImportError: + bz2 = None + +def md5sum(data): + return md5(data).hexdigest() + +TEMPDIR = os.path.abspath(test_support.TESTFN) +tarname = test_support.findfile("testtar.tar") +gzipname = os.path.join(TEMPDIR, "testtar.tar.gz") +bz2name = os.path.join(TEMPDIR, "testtar.tar.bz2") +tmpname = os.path.join(TEMPDIR, "tmp.tar") + +md5_regtype = "65f477c818ad9e15f7feab0c6d37742f" +md5_sparse = "a54fbc4ca4f4399a90e1b27164012fc6" + + +class ReadTest(unittest.TestCase): + + tarname = tarname + mode = "r:" + + def setUp(self): + self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1") + + def tearDown(self): + self.tar.close() + + +class UstarReadTest(ReadTest): + + def test_fileobj_regular_file(self): + tarinfo = self.tar.getmember("ustar/regtype") + fobj = self.tar.extractfile(tarinfo) + data = fobj.read() + self.assertTrue((len(data), md5sum(data)) == (tarinfo.size, md5_regtype), + "regular file extraction failed") + + def test_fileobj_readlines(self): + self.tar.extract("ustar/regtype", TEMPDIR) + tarinfo = self.tar.getmember("ustar/regtype") + fobj1 = open(os.path.join(TEMPDIR, "ustar/regtype"), "rU") + fobj2 = self.tar.extractfile(tarinfo) + + lines1 = fobj1.readlines() + lines2 = fobj2.readlines() + self.assertTrue(lines1 == lines2, + "fileobj.readlines() failed") + self.assertTrue(len(lines2) == 114, + "fileobj.readlines() failed") + self.assertTrue(lines2[83] == + "I will gladly admit that Python is not the fastest running scripting language.\n", + "fileobj.readlines() failed") + + def test_fileobj_iter(self): + self.tar.extract("ustar/regtype", TEMPDIR) + tarinfo = self.tar.getmember("ustar/regtype") + fobj1 = open(os.path.join(TEMPDIR, "ustar/regtype"), "rU") + fobj2 = self.tar.extractfile(tarinfo) + lines1 = fobj1.readlines() + lines2 = [line for line in fobj2] + self.assertTrue(lines1 == lines2, + "fileobj.__iter__() failed") + + def test_fileobj_seek(self): + self.tar.extract("ustar/regtype", TEMPDIR) + fobj = open(os.path.join(TEMPDIR, "ustar/regtype"), "rb") + data = fobj.read() + fobj.close() + + tarinfo = self.tar.getmember("ustar/regtype") + fobj = self.tar.extractfile(tarinfo) + + text = fobj.read() + fobj.seek(0) + self.assertTrue(0 == fobj.tell(), + "seek() to file's start failed") + fobj.seek(2048, 0) + self.assertTrue(2048 == fobj.tell(), + "seek() to absolute position failed") + fobj.seek(-1024, 1) + self.assertTrue(1024 == fobj.tell(), + "seek() to negative relative position failed") + fobj.seek(1024, 1) + self.assertTrue(2048 == fobj.tell(), + "seek() to positive relative position failed") + s = fobj.read(10) + self.assertTrue(s == data[2048:2058], + "read() after seek failed") + fobj.seek(0, 2) + self.assertTrue(tarinfo.size == fobj.tell(), + "seek() to file's end failed") + self.assertTrue(fobj.read() == "", + "read() at file's end did not return empty string") + fobj.seek(-tarinfo.size, 2) + self.assertTrue(0 == fobj.tell(), + "relative seek() to file's start failed") + fobj.seek(512) + s1 = fobj.readlines() + fobj.seek(512) + s2 = fobj.readlines() + self.assertTrue(s1 == s2, + "readlines() after seek failed") + fobj.seek(0) + self.assertTrue(len(fobj.readline()) == fobj.tell(), + "tell() after readline() failed") + fobj.seek(512) + self.assertTrue(len(fobj.readline()) + 512 == fobj.tell(), + "tell() after seek() and readline() failed") + fobj.seek(0) + line = fobj.readline() + self.assertTrue(fobj.read() == data[len(line):], + "read() after readline() failed") + fobj.close() + + # Test if symbolic and hard links are resolved by extractfile(). The + # test link members each point to a regular member whose data is + # supposed to be exported. + def _test_fileobj_link(self, lnktype, regtype): + a = self.tar.extractfile(lnktype) + b = self.tar.extractfile(regtype) + self.assertEqual(a.name, b.name) + + def test_fileobj_link1(self): + self._test_fileobj_link("ustar/lnktype", "ustar/regtype") + + def test_fileobj_link2(self): + self._test_fileobj_link("./ustar/linktest2/lnktype", "ustar/linktest1/regtype") + + def test_fileobj_symlink1(self): + self._test_fileobj_link("ustar/symtype", "ustar/regtype") + + def test_fileobj_symlink2(self): + self._test_fileobj_link("./ustar/linktest2/symtype", "ustar/linktest1/regtype") + + def test_issue14160(self): + self._test_fileobj_link("symtype2", "ustar/regtype") + + +class CommonReadTest(ReadTest): + + def test_empty_tarfile(self): + # Test for issue6123: Allow opening empty archives. + # This test checks if tarfile.open() is able to open an empty tar + # archive successfully. Note that an empty tar archive is not the + # same as an empty file! + tarfile.open(tmpname, self.mode.replace("r", "w")).close() + try: + tar = tarfile.open(tmpname, self.mode) + tar.getnames() + except tarfile.ReadError: + self.fail("tarfile.open() failed on empty archive") + self.assertListEqual(tar.getmembers(), []) + + def test_null_tarfile(self): + # Test for issue6123: Allow opening empty archives. + # This test guarantees that tarfile.open() does not treat an empty + # file as an empty tar archive. + open(tmpname, "wb").close() + self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, self.mode) + self.assertRaises(tarfile.ReadError, tarfile.open, tmpname) + + def test_ignore_zeros(self): + # Test TarFile's ignore_zeros option. + if self.mode.endswith(":gz"): + _open = gzip.GzipFile + elif self.mode.endswith(":bz2"): + _open = bz2.BZ2File + else: + _open = open + + for char in ('\0', 'a'): + # Test if EOFHeaderError ('\0') and InvalidHeaderError ('a') + # are ignored correctly. + fobj = _open(tmpname, "wb") + fobj.write(char * 1024) + fobj.write(tarfile.TarInfo("foo").tobuf()) + fobj.close() + + tar = tarfile.open(tmpname, mode="r", ignore_zeros=True) + self.assertListEqual(tar.getnames(), ["foo"], + "ignore_zeros=True should have skipped the %r-blocks" % char) + tar.close() + + +class MiscReadTest(CommonReadTest): + + def test_no_name_argument(self): + fobj = open(self.tarname, "rb") + tar = tarfile.open(fileobj=fobj, mode=self.mode) + self.assertEqual(tar.name, os.path.abspath(fobj.name)) + + def test_no_name_attribute(self): + data = open(self.tarname, "rb").read() + fobj = StringIO.StringIO(data) + self.assertRaises(AttributeError, getattr, fobj, "name") + tar = tarfile.open(fileobj=fobj, mode=self.mode) + self.assertEqual(tar.name, None) + + def test_empty_name_attribute(self): + data = open(self.tarname, "rb").read() + fobj = StringIO.StringIO(data) + fobj.name = "" + tar = tarfile.open(fileobj=fobj, mode=self.mode) + self.assertEqual(tar.name, None) + + def test_fileobj_with_offset(self): + # Skip the first member and store values from the second member + # of the testtar. + tar = tarfile.open(self.tarname, mode=self.mode) + tar.next() + t = tar.next() + name = t.name + offset = t.offset + data = tar.extractfile(t).read() + tar.close() + + # Open the testtar and seek to the offset of the second member. + if self.mode.endswith(":gz"): + _open = gzip.GzipFile + elif self.mode.endswith(":bz2"): + _open = bz2.BZ2File + else: + _open = open + fobj = _open(self.tarname, "rb") + fobj.seek(offset) + + # Test if the tarfile starts with the second member. + tar = tar.open(self.tarname, mode="r:", fileobj=fobj) + t = tar.next() + self.assertEqual(t.name, name) + # Read to the end of fileobj and test if seeking back to the + # beginning works. + tar.getmembers() + self.assertEqual(tar.extractfile(t).read(), data, + "seek back did not work") + tar.close() + + def test_fail_comp(self): + # For Gzip and Bz2 Tests: fail with a ReadError on an uncompressed file. + if self.mode == "r:": + return + self.assertRaises(tarfile.ReadError, tarfile.open, tarname, self.mode) + fobj = open(tarname, "rb") + self.assertRaises(tarfile.ReadError, tarfile.open, fileobj=fobj, mode=self.mode) + + def test_v7_dirtype(self): + # Test old style dirtype member (bug #1336623): + # Old V7 tars create directory members using an AREGTYPE + # header with a "/" appended to the filename field. + tarinfo = self.tar.getmember("misc/dirtype-old-v7") + self.assertTrue(tarinfo.type == tarfile.DIRTYPE, + "v7 dirtype failed") + + def test_xstar_type(self): + # The xstar format stores extra atime and ctime fields inside the + # space reserved for the prefix field. The prefix field must be + # ignored in this case, otherwise it will mess up the name. + try: + self.tar.getmember("misc/regtype-xstar") + except KeyError: + self.fail("failed to find misc/regtype-xstar (mangled prefix?)") + + def test_check_members(self): + for tarinfo in self.tar: + self.assertTrue(int(tarinfo.mtime) == 07606136617, + "wrong mtime for %s" % tarinfo.name) + if not tarinfo.name.startswith("ustar/"): + continue + self.assertTrue(tarinfo.uname == "tarfile", + "wrong uname for %s" % tarinfo.name) + + def test_find_members(self): + self.assertTrue(self.tar.getmembers()[-1].name == "misc/eof", + "could not find all members") + + def test_extract_hardlink(self): + # Test hardlink extraction (e.g. bug #857297). + with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar: + tar.extract("ustar/regtype", TEMPDIR) + self.addCleanup(os.remove, os.path.join(TEMPDIR, "ustar/regtype")) + + tar.extract("ustar/lnktype", TEMPDIR) + self.addCleanup(os.remove, os.path.join(TEMPDIR, "ustar/lnktype")) + with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f: + data = f.read() + self.assertEqual(md5sum(data), md5_regtype) + + tar.extract("ustar/symtype", TEMPDIR) + self.addCleanup(os.remove, os.path.join(TEMPDIR, "ustar/symtype")) + with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f: + data = f.read() + self.assertEqual(md5sum(data), md5_regtype) + + def test_extractall(self): + # Test if extractall() correctly restores directory permissions + # and times (see issue1735). + tar = tarfile.open(tarname, encoding="iso8859-1") + directories = [t for t in tar if t.isdir()] + tar.extractall(TEMPDIR, directories) + for tarinfo in directories: + path = os.path.join(TEMPDIR, tarinfo.name) + if sys.platform != "win32": + # Win32 has no support for fine grained permissions. + self.assertEqual(tarinfo.mode & 0777, os.stat(path).st_mode & 0777) + self.assertEqual(tarinfo.mtime, os.path.getmtime(path)) + tar.close() + + def test_init_close_fobj(self): + # Issue #7341: Close the internal file object in the TarFile + # constructor in case of an error. For the test we rely on + # the fact that opening an empty file raises a ReadError. + empty = os.path.join(TEMPDIR, "empty") + open(empty, "wb").write("") + + try: + tar = object.__new__(tarfile.TarFile) + try: + tar.__init__(empty) + except tarfile.ReadError: + self.assertTrue(tar.fileobj.closed) + else: + self.fail("ReadError not raised") + finally: + os.remove(empty) + + +class StreamReadTest(CommonReadTest): + + mode="r|" + + def test_fileobj_regular_file(self): + tarinfo = self.tar.next() # get "regtype" (can't use getmember) + fobj = self.tar.extractfile(tarinfo) + data = fobj.read() + self.assertTrue((len(data), md5sum(data)) == (tarinfo.size, md5_regtype), + "regular file extraction failed") + + def test_provoke_stream_error(self): + tarinfos = self.tar.getmembers() + f = self.tar.extractfile(tarinfos[0]) # read the first member + self.assertRaises(tarfile.StreamError, f.read) + + def test_compare_members(self): + tar1 = tarfile.open(tarname, encoding="iso8859-1") + tar2 = self.tar + + while True: + t1 = tar1.next() + t2 = tar2.next() + if t1 is None: + break + self.assertTrue(t2 is not None, "stream.next() failed.") + + if t2.islnk() or t2.issym(): + self.assertRaises(tarfile.StreamError, tar2.extractfile, t2) + continue + + v1 = tar1.extractfile(t1) + v2 = tar2.extractfile(t2) + if v1 is None: + continue + self.assertTrue(v2 is not None, "stream.extractfile() failed") + self.assertTrue(v1.read() == v2.read(), "stream extraction failed") + + tar1.close() + + +class DetectReadTest(unittest.TestCase): + + def _testfunc_file(self, name, mode): + try: + tarfile.open(name, mode) + except tarfile.ReadError: + self.fail() + + def _testfunc_fileobj(self, name, mode): + try: + tarfile.open(name, mode, fileobj=open(name, "rb")) + except tarfile.ReadError: + self.fail() + + def _test_modes(self, testfunc): + testfunc(tarname, "r") + testfunc(tarname, "r:") + testfunc(tarname, "r:*") + testfunc(tarname, "r|") + testfunc(tarname, "r|*") + + if gzip: + self.assertRaises(tarfile.ReadError, tarfile.open, tarname, mode="r:gz") + self.assertRaises(tarfile.ReadError, tarfile.open, tarname, mode="r|gz") + self.assertRaises(tarfile.ReadError, tarfile.open, gzipname, mode="r:") + self.assertRaises(tarfile.ReadError, tarfile.open, gzipname, mode="r|") + + testfunc(gzipname, "r") + testfunc(gzipname, "r:*") + testfunc(gzipname, "r:gz") + testfunc(gzipname, "r|*") + testfunc(gzipname, "r|gz") + + if bz2: + self.assertRaises(tarfile.ReadError, tarfile.open, tarname, mode="r:bz2") + self.assertRaises(tarfile.ReadError, tarfile.open, tarname, mode="r|bz2") + self.assertRaises(tarfile.ReadError, tarfile.open, bz2name, mode="r:") + self.assertRaises(tarfile.ReadError, tarfile.open, bz2name, mode="r|") + + testfunc(bz2name, "r") + testfunc(bz2name, "r:*") + testfunc(bz2name, "r:bz2") + testfunc(bz2name, "r|*") + testfunc(bz2name, "r|bz2") + + def test_detect_file(self): + self._test_modes(self._testfunc_file) + + def test_detect_fileobj(self): + self._test_modes(self._testfunc_fileobj) + + def test_detect_stream_bz2(self): + # Originally, tarfile's stream detection looked for the string + # "BZh91" at the start of the file. This is incorrect because + # the '9' represents the blocksize (900kB). If the file was + # compressed using another blocksize autodetection fails. + if not bz2: + return + + with open(tarname, "rb") as fobj: + data = fobj.read() + + # Compress with blocksize 100kB, the file starts with "BZh11". + with bz2.BZ2File(tmpname, "wb", compresslevel=1) as fobj: + fobj.write(data) + + self._testfunc_file(tmpname, "r|*") + + +class MemberReadTest(ReadTest): + + def _test_member(self, tarinfo, chksum=None, **kwargs): + if chksum is not None: + self.assertTrue(md5sum(self.tar.extractfile(tarinfo).read()) == chksum, + "wrong md5sum for %s" % tarinfo.name) + + kwargs["mtime"] = 07606136617 + kwargs["uid"] = 1000 + kwargs["gid"] = 100 + if "old-v7" not in tarinfo.name: + # V7 tar can't handle alphabetic owners. + kwargs["uname"] = "tarfile" + kwargs["gname"] = "tarfile" + for k, v in kwargs.iteritems(): + self.assertTrue(getattr(tarinfo, k) == v, + "wrong value in %s field of %s" % (k, tarinfo.name)) + + def test_find_regtype(self): + tarinfo = self.tar.getmember("ustar/regtype") + self._test_member(tarinfo, size=7011, chksum=md5_regtype) + + def test_find_conttype(self): + tarinfo = self.tar.getmember("ustar/conttype") + self._test_member(tarinfo, size=7011, chksum=md5_regtype) + + def test_find_dirtype(self): + tarinfo = self.tar.getmember("ustar/dirtype") + self._test_member(tarinfo, size=0) + + def test_find_dirtype_with_size(self): + tarinfo = self.tar.getmember("ustar/dirtype-with-size") + self._test_member(tarinfo, size=255) + + def test_find_lnktype(self): + tarinfo = self.tar.getmember("ustar/lnktype") + self._test_member(tarinfo, size=0, linkname="ustar/regtype") + + def test_find_symtype(self): + tarinfo = self.tar.getmember("ustar/symtype") + self._test_member(tarinfo, size=0, linkname="regtype") + + def test_find_blktype(self): + tarinfo = self.tar.getmember("ustar/blktype") + self._test_member(tarinfo, size=0, devmajor=3, devminor=0) + + def test_find_chrtype(self): + tarinfo = self.tar.getmember("ustar/chrtype") + self._test_member(tarinfo, size=0, devmajor=1, devminor=3) + + def test_find_fifotype(self): + tarinfo = self.tar.getmember("ustar/fifotype") + self._test_member(tarinfo, size=0) + + def test_find_sparse(self): + tarinfo = self.tar.getmember("ustar/sparse") + self._test_member(tarinfo, size=86016, chksum=md5_sparse) + + def test_find_umlauts(self): + tarinfo = self.tar.getmember("ustar/umlauts-???????") + self._test_member(tarinfo, size=7011, chksum=md5_regtype) + + def test_find_ustar_longname(self): + name = "ustar/" + "12345/" * 39 + "1234567/longname" + self.assertIn(name, self.tar.getnames()) + + def test_find_regtype_oldv7(self): + tarinfo = self.tar.getmember("misc/regtype-old-v7") + self._test_member(tarinfo, size=7011, chksum=md5_regtype) + + def test_find_pax_umlauts(self): + self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1") + tarinfo = self.tar.getmember("pax/umlauts-???????") + self._test_member(tarinfo, size=7011, chksum=md5_regtype) + + +class LongnameTest(ReadTest): + + def test_read_longname(self): + # Test reading of longname (bug #1471427). + longname = self.subdir + "/" + "123/" * 125 + "longname" + try: + tarinfo = self.tar.getmember(longname) + except KeyError: + self.fail("longname not found") + self.assertTrue(tarinfo.type != tarfile.DIRTYPE, "read longname as dirtype") + + def test_read_longlink(self): + longname = self.subdir + "/" + "123/" * 125 + "longname" + longlink = self.subdir + "/" + "123/" * 125 + "longlink" + try: + tarinfo = self.tar.getmember(longlink) + except KeyError: + self.fail("longlink not found") + self.assertTrue(tarinfo.linkname == longname, "linkname wrong") + + def test_truncated_longname(self): + longname = self.subdir + "/" + "123/" * 125 + "longname" + tarinfo = self.tar.getmember(longname) + offset = tarinfo.offset + self.tar.fileobj.seek(offset) + fobj = StringIO.StringIO(self.tar.fileobj.read(3 * 512)) + self.assertRaises(tarfile.ReadError, tarfile.open, name="foo.tar", fileobj=fobj) + + def test_header_offset(self): + # Test if the start offset of the TarInfo object includes + # the preceding extended header. + longname = self.subdir + "/" + "123/" * 125 + "longname" + offset = self.tar.getmember(longname).offset + fobj = open(tarname) + fobj.seek(offset) + tarinfo = tarfile.TarInfo.frombuf(fobj.read(512)) + self.assertEqual(tarinfo.type, self.longnametype) + + +class GNUReadTest(LongnameTest): + + subdir = "gnu" + longnametype = tarfile.GNUTYPE_LONGNAME + + def test_sparse_file(self): + tarinfo1 = self.tar.getmember("ustar/sparse") + fobj1 = self.tar.extractfile(tarinfo1) + tarinfo2 = self.tar.getmember("gnu/sparse") + fobj2 = self.tar.extractfile(tarinfo2) + self.assertTrue(fobj1.read() == fobj2.read(), + "sparse file extraction failed") + + +class PaxReadTest(LongnameTest): + + subdir = "pax" + longnametype = tarfile.XHDTYPE + + def test_pax_global_headers(self): + tar = tarfile.open(tarname, encoding="iso8859-1") + + tarinfo = tar.getmember("pax/regtype1") + self.assertEqual(tarinfo.uname, "foo") + self.assertEqual(tarinfo.gname, "bar") + self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), u"???????") + + tarinfo = tar.getmember("pax/regtype2") + self.assertEqual(tarinfo.uname, "") + self.assertEqual(tarinfo.gname, "bar") + self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), u"???????") + + tarinfo = tar.getmember("pax/regtype3") + self.assertEqual(tarinfo.uname, "tarfile") + self.assertEqual(tarinfo.gname, "tarfile") + self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), u"???????") + + def test_pax_number_fields(self): + # All following number fields are read from the pax header. + tar = tarfile.open(tarname, encoding="iso8859-1") + tarinfo = tar.getmember("pax/regtype4") + self.assertEqual(tarinfo.size, 7011) + self.assertEqual(tarinfo.uid, 123) + self.assertEqual(tarinfo.gid, 123) + self.assertEqual(tarinfo.mtime, 1041808783.0) + self.assertEqual(type(tarinfo.mtime), float) + self.assertEqual(float(tarinfo.pax_headers["atime"]), 1041808783.0) + self.assertEqual(float(tarinfo.pax_headers["ctime"]), 1041808783.0) + + +class WriteTestBase(unittest.TestCase): + # Put all write tests in here that are supposed to be tested + # in all possible mode combinations. + + def test_fileobj_no_close(self): + fobj = StringIO.StringIO() + tar = tarfile.open(fileobj=fobj, mode=self.mode) + tar.addfile(tarfile.TarInfo("foo")) + tar.close() + self.assertTrue(fobj.closed is False, "external fileobjs must never closed") + + +class WriteTest(WriteTestBase): + + mode = "w:" + + def test_100_char_name(self): + # The name field in a tar header stores strings of at most 100 chars. + # If a string is shorter than 100 chars it has to be padded with '\0', + # which implies that a string of exactly 100 chars is stored without + # a trailing '\0'. + name = "0123456789" * 10 + tar = tarfile.open(tmpname, self.mode) + t = tarfile.TarInfo(name) + tar.addfile(t) + tar.close() + + tar = tarfile.open(tmpname) + self.assertTrue(tar.getnames()[0] == name, + "failed to store 100 char filename") + tar.close() + + def test_tar_size(self): + # Test for bug #1013882. + tar = tarfile.open(tmpname, self.mode) + path = os.path.join(TEMPDIR, "file") + fobj = open(path, "wb") + fobj.write("aaa") + fobj.close() + tar.add(path) + tar.close() + self.assertTrue(os.path.getsize(tmpname) > 0, + "tarfile is empty") + + # The test_*_size tests test for bug #1167128. + def test_file_size(self): + tar = tarfile.open(tmpname, self.mode) + + path = os.path.join(TEMPDIR, "file") + fobj = open(path, "wb") + fobj.close() + tarinfo = tar.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + + fobj = open(path, "wb") + fobj.write("aaa") + fobj.close() + tarinfo = tar.gettarinfo(path) + self.assertEqual(tarinfo.size, 3) + + tar.close() + + def test_directory_size(self): + path = os.path.join(TEMPDIR, "directory") + os.mkdir(path) + try: + tar = tarfile.open(tmpname, self.mode) + tarinfo = tar.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + finally: + os.rmdir(path) + + def test_link_size(self): + if hasattr(os, "link"): + link = os.path.join(TEMPDIR, "link") + target = os.path.join(TEMPDIR, "link_target") + fobj = open(target, "wb") + fobj.write("aaa") + fobj.close() + os.link(target, link) + try: + tar = tarfile.open(tmpname, self.mode) + # Record the link target in the inodes list. + tar.gettarinfo(target) + tarinfo = tar.gettarinfo(link) + self.assertEqual(tarinfo.size, 0) + finally: + os.remove(target) + os.remove(link) + + def test_symlink_size(self): + if hasattr(os, "symlink"): + path = os.path.join(TEMPDIR, "symlink") + os.symlink("link_target", path) + try: + tar = tarfile.open(tmpname, self.mode) + tarinfo = tar.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + finally: + os.remove(path) + + def test_add_self(self): + # Test for #1257255. + dstname = os.path.abspath(tmpname) + + tar = tarfile.open(tmpname, self.mode) + self.assertTrue(tar.name == dstname, "archive name must be absolute") + + tar.add(dstname) + self.assertTrue(tar.getnames() == [], "added the archive to itself") + + cwd = os.getcwd() + os.chdir(TEMPDIR) + tar.add(dstname) + os.chdir(cwd) + self.assertTrue(tar.getnames() == [], "added the archive to itself") + + def test_exclude(self): + tempdir = os.path.join(TEMPDIR, "exclude") + os.mkdir(tempdir) + try: + for name in ("foo", "bar", "baz"): + name = os.path.join(tempdir, name) + open(name, "wb").close() + + exclude = os.path.isfile + + tar = tarfile.open(tmpname, self.mode, encoding="iso8859-1") + with test_support.check_warnings(("use the filter argument", + DeprecationWarning)): + tar.add(tempdir, arcname="empty_dir", exclude=exclude) + tar.close() + + tar = tarfile.open(tmpname, "r") + self.assertEqual(len(tar.getmembers()), 1) + self.assertEqual(tar.getnames()[0], "empty_dir") + finally: + shutil.rmtree(tempdir) + + def test_filter(self): + tempdir = os.path.join(TEMPDIR, "filter") + os.mkdir(tempdir) + try: + for name in ("foo", "bar", "baz"): + name = os.path.join(tempdir, name) + open(name, "wb").close() + + def filter(tarinfo): + if os.path.basename(tarinfo.name) == "bar": + return + tarinfo.uid = 123 + tarinfo.uname = "foo" + return tarinfo + + tar = tarfile.open(tmpname, self.mode, encoding="iso8859-1") + tar.add(tempdir, arcname="empty_dir", filter=filter) + tar.close() + + tar = tarfile.open(tmpname, "r") + for tarinfo in tar: + self.assertEqual(tarinfo.uid, 123) + self.assertEqual(tarinfo.uname, "foo") + self.assertEqual(len(tar.getmembers()), 3) + tar.close() + finally: + shutil.rmtree(tempdir) + + # Guarantee that stored pathnames are not modified. Don't + # remove ./ or ../ or double slashes. Still make absolute + # pathnames relative. + # For details see bug #6054. + def _test_pathname(self, path, cmp_path=None, dir=False): + # Create a tarfile with an empty member named path + # and compare the stored name with the original. + foo = os.path.join(TEMPDIR, "foo") + if not dir: + open(foo, "w").close() + else: + os.mkdir(foo) + + tar = tarfile.open(tmpname, self.mode) + tar.add(foo, arcname=path) + tar.close() + + tar = tarfile.open(tmpname, "r") + t = tar.next() + tar.close() + + if not dir: + os.remove(foo) + else: + os.rmdir(foo) + + self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/")) + + def test_pathnames(self): + self._test_pathname("foo") + self._test_pathname(os.path.join("foo", ".", "bar")) + self._test_pathname(os.path.join("foo", "..", "bar")) + self._test_pathname(os.path.join(".", "foo")) + self._test_pathname(os.path.join(".", "foo", ".")) + self._test_pathname(os.path.join(".", "foo", ".", "bar")) + self._test_pathname(os.path.join(".", "foo", "..", "bar")) + self._test_pathname(os.path.join(".", "foo", "..", "bar")) + self._test_pathname(os.path.join("..", "foo")) + self._test_pathname(os.path.join("..", "foo", "..")) + self._test_pathname(os.path.join("..", "foo", ".", "bar")) + self._test_pathname(os.path.join("..", "foo", "..", "bar")) + + self._test_pathname("foo" + os.sep + os.sep + "bar") + self._test_pathname("foo" + os.sep + os.sep, "foo", dir=True) + + def test_abs_pathnames(self): + if sys.platform == "win32": + self._test_pathname("C:\\foo", "foo") + else: + self._test_pathname("/foo", "foo") + self._test_pathname("///foo", "foo") + + def test_cwd(self): + # Test adding the current working directory. + cwd = os.getcwd() + os.chdir(TEMPDIR) + try: + open("foo", "w").close() + + tar = tarfile.open(tmpname, self.mode) + tar.add(".") + tar.close() + + tar = tarfile.open(tmpname, "r") + for t in tar: + self.assertTrue(t.name == "." or t.name.startswith("./")) + tar.close() + finally: + os.chdir(cwd) + + @unittest.skipUnless(hasattr(os, 'symlink'), "needs os.symlink") + def test_extractall_symlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file, arcname=os.path.basename(source_file)) + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + + @unittest.skipUnless(hasattr(os, 'symlink'), "needs os.symlink") + def test_extractall_broken_symlinks(self): + # Test if extractall works properly when tarfile contains broken + # symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # remove the real file + os.unlink(source_file) + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with broken symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + + @unittest.skipUnless(hasattr(os, 'link'), "needs os.link") + def test_extractall_hardlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.link(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file, arcname=os.path.basename(source_file)) + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with linked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + +class StreamWriteTest(WriteTestBase): + + mode = "w|" + + def test_stream_padding(self): + # Test for bug #1543303. + tar = tarfile.open(tmpname, self.mode) + tar.close() + + if self.mode.endswith("gz"): + fobj = gzip.GzipFile(tmpname) + data = fobj.read() + fobj.close() + elif self.mode.endswith("bz2"): + dec = bz2.BZ2Decompressor() + data = open(tmpname, "rb").read() + data = dec.decompress(data) + self.assertTrue(len(dec.unused_data) == 0, + "found trailing data") + else: + fobj = open(tmpname, "rb") + data = fobj.read() + fobj.close() + + self.assertTrue(data.count("\0") == tarfile.RECORDSIZE, + "incorrect zero padding") + + def test_file_mode(self): + # Test for issue #8464: Create files with correct + # permissions. + if sys.platform == "win32" or not hasattr(os, "umask"): + return + + if os.path.exists(tmpname): + os.remove(tmpname) + + original_umask = os.umask(0022) + try: + tar = tarfile.open(tmpname, self.mode) + tar.close() + mode = os.stat(tmpname).st_mode & 0777 + self.assertEqual(mode, 0644, "wrong file permissions") + finally: + os.umask(original_umask) + + def test_issue13639(self): + try: + with tarfile.open(unicode(tmpname, sys.getfilesystemencoding()), self.mode): + pass + except UnicodeDecodeError: + self.fail("_Stream failed to write unicode filename") + + +class GNUWriteTest(unittest.TestCase): + # This testcase checks for correct creation of GNU Longname + # and Longlink extended headers (cp. bug #812325). + + def _length(self, s): + blocks, remainder = divmod(len(s) + 1, 512) + if remainder: + blocks += 1 + return blocks * 512 + + def _calc_size(self, name, link=None): + # Initial tar header + count = 512 + + if len(name) > tarfile.LENGTH_NAME: + # GNU longname extended header + longname + count += 512 + count += self._length(name) + if link is not None and len(link) > tarfile.LENGTH_LINK: + # GNU longlink extended header + longlink + count += 512 + count += self._length(link) + return count + + def _test(self, name, link=None): + tarinfo = tarfile.TarInfo(name) + if link: + tarinfo.linkname = link + tarinfo.type = tarfile.LNKTYPE + + tar = tarfile.open(tmpname, "w") + tar.format = tarfile.GNU_FORMAT + tar.addfile(tarinfo) + + v1 = self._calc_size(name, link) + v2 = tar.offset + self.assertTrue(v1 == v2, "GNU longname/longlink creation failed") + + tar.close() + + tar = tarfile.open(tmpname) + member = tar.next() + self.assertIsNotNone(member, + "unable to read longname member") + self.assertEqual(tarinfo.name, member.name, + "unable to read longname member") + self.assertEqual(tarinfo.linkname, member.linkname, + "unable to read longname member") + + def test_longname_1023(self): + self._test(("longnam/" * 127) + "longnam") + + def test_longname_1024(self): + self._test(("longnam/" * 127) + "longname") + + def test_longname_1025(self): + self._test(("longnam/" * 127) + "longname_") + + def test_longlink_1023(self): + self._test("name", ("longlnk/" * 127) + "longlnk") + + def test_longlink_1024(self): + self._test("name", ("longlnk/" * 127) + "longlink") + + def test_longlink_1025(self): + self._test("name", ("longlnk/" * 127) + "longlink_") + + def test_longnamelink_1023(self): + self._test(("longnam/" * 127) + "longnam", + ("longlnk/" * 127) + "longlnk") + + def test_longnamelink_1024(self): + self._test(("longnam/" * 127) + "longname", + ("longlnk/" * 127) + "longlink") + + def test_longnamelink_1025(self): + self._test(("longnam/" * 127) + "longname_", + ("longlnk/" * 127) + "longlink_") + + +class HardlinkTest(unittest.TestCase): + # Test the creation of LNKTYPE (hardlink) members in an archive. + + def setUp(self): + self.foo = os.path.join(TEMPDIR, "foo") + self.bar = os.path.join(TEMPDIR, "bar") + + fobj = open(self.foo, "wb") + fobj.write("foo") + fobj.close() + + os.link(self.foo, self.bar) + + self.tar = tarfile.open(tmpname, "w") + self.tar.add(self.foo) + + def tearDown(self): + self.tar.close() + os.remove(self.foo) + os.remove(self.bar) + + def test_add_twice(self): + # The same name will be added as a REGTYPE every + # time regardless of st_nlink. + tarinfo = self.tar.gettarinfo(self.foo) + self.assertTrue(tarinfo.type == tarfile.REGTYPE, + "add file as regular failed") + + def test_add_hardlink(self): + tarinfo = self.tar.gettarinfo(self.bar) + self.assertTrue(tarinfo.type == tarfile.LNKTYPE, + "add file as hardlink failed") + + def test_dereference_hardlink(self): + self.tar.dereference = True + tarinfo = self.tar.gettarinfo(self.bar) + self.assertTrue(tarinfo.type == tarfile.REGTYPE, + "dereferencing hardlink failed") + + +class PaxWriteTest(GNUWriteTest): + + def _test(self, name, link=None): + # See GNUWriteTest. + tarinfo = tarfile.TarInfo(name) + if link: + tarinfo.linkname = link + tarinfo.type = tarfile.LNKTYPE + + tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT) + tar.addfile(tarinfo) + tar.close() + + tar = tarfile.open(tmpname) + if link: + l = tar.getmembers()[0].linkname + self.assertTrue(link == l, "PAX longlink creation failed") + else: + n = tar.getmembers()[0].name + self.assertTrue(name == n, "PAX longname creation failed") + + def test_pax_global_header(self): + pax_headers = { + u"foo": u"bar", + u"uid": u"0", + u"mtime": u"1.23", + u"test": u"???", + u"???": u"test"} + + tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT, + pax_headers=pax_headers) + tar.addfile(tarfile.TarInfo("test")) + tar.close() + + # Test if the global header was written correctly. + tar = tarfile.open(tmpname, encoding="iso8859-1") + self.assertEqual(tar.pax_headers, pax_headers) + self.assertEqual(tar.getmembers()[0].pax_headers, pax_headers) + + # Test if all the fields are unicode. + for key, val in tar.pax_headers.iteritems(): + self.assertTrue(type(key) is unicode) + self.assertTrue(type(val) is unicode) + if key in tarfile.PAX_NUMBER_FIELDS: + try: + tarfile.PAX_NUMBER_FIELDS[key](val) + except (TypeError, ValueError): + self.fail("unable to convert pax header field") + + def test_pax_extended_header(self): + # The fields from the pax header have priority over the + # TarInfo. + pax_headers = {u"path": u"foo", u"uid": u"123"} + + tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT, encoding="iso8859-1") + t = tarfile.TarInfo() + t.name = u"???" # non-ASCII + t.uid = 8**8 # too large + t.pax_headers = pax_headers + tar.addfile(t) + tar.close() + + tar = tarfile.open(tmpname, encoding="iso8859-1") + t = tar.getmembers()[0] + self.assertEqual(t.pax_headers, pax_headers) + self.assertEqual(t.name, "foo") + self.assertEqual(t.uid, 123) + + +class UstarUnicodeTest(unittest.TestCase): + # All *UnicodeTests FIXME + + format = tarfile.USTAR_FORMAT + + def test_iso8859_1_filename(self): + self._test_unicode_filename("iso8859-1") + + def test_utf7_filename(self): + self._test_unicode_filename("utf7") + + def test_utf8_filename(self): + self._test_unicode_filename("utf8") + + def _test_unicode_filename(self, encoding): + tar = tarfile.open(tmpname, "w", format=self.format, encoding=encoding, errors="strict") + name = u"???" + tar.addfile(tarfile.TarInfo(name)) + tar.close() + + tar = tarfile.open(tmpname, encoding=encoding) + self.assertTrue(type(tar.getnames()[0]) is not unicode) + self.assertEqual(tar.getmembers()[0].name, name.encode(encoding)) + tar.close() + + def test_unicode_filename_error(self): + tar = tarfile.open(tmpname, "w", format=self.format, encoding="ascii", errors="strict") + tarinfo = tarfile.TarInfo() + + tarinfo.name = "???" + if self.format == tarfile.PAX_FORMAT: + self.assertRaises(UnicodeError, tar.addfile, tarinfo) + else: + tar.addfile(tarinfo) + + tarinfo.name = u"???" + self.assertRaises(UnicodeError, tar.addfile, tarinfo) + + tarinfo.name = "foo" + tarinfo.uname = u"???" + self.assertRaises(UnicodeError, tar.addfile, tarinfo) + + def test_unicode_argument(self): + tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict") + for t in tar: + self.assertTrue(type(t.name) is str) + self.assertTrue(type(t.linkname) is str) + self.assertTrue(type(t.uname) is str) + self.assertTrue(type(t.gname) is str) + tar.close() + + def test_uname_unicode(self): + for name in (u"???", "???"): + t = tarfile.TarInfo("foo") + t.uname = name + t.gname = name + + fobj = StringIO.StringIO() + tar = tarfile.open("foo.tar", mode="w", fileobj=fobj, format=self.format, encoding="iso8859-1") + tar.addfile(t) + tar.close() + fobj.seek(0) + + tar = tarfile.open("foo.tar", fileobj=fobj, encoding="iso8859-1") + t = tar.getmember("foo") + self.assertEqual(t.uname, "???") + self.assertEqual(t.gname, "???") + + +class GNUUnicodeTest(UstarUnicodeTest): + + format = tarfile.GNU_FORMAT + + +class PaxUnicodeTest(UstarUnicodeTest): + + format = tarfile.PAX_FORMAT + + def _create_unicode_name(self, name): + tar = tarfile.open(tmpname, "w", format=self.format) + t = tarfile.TarInfo() + t.pax_headers["path"] = name + tar.addfile(t) + tar.close() + + def test_error_handlers(self): + # Test if the unicode error handlers work correctly for characters + # that cannot be expressed in a given encoding. + self._create_unicode_name(u"???") + + for handler, name in (("utf-8", u"???".encode("utf8")), + ("replace", "???"), ("ignore", "")): + tar = tarfile.open(tmpname, format=self.format, encoding="ascii", + errors=handler) + self.assertEqual(tar.getnames()[0], name) + + self.assertRaises(UnicodeError, tarfile.open, tmpname, + encoding="ascii", errors="strict") + + def test_error_handler_utf8(self): + # Create a pathname that has one component representable using + # iso8859-1 and the other only in iso8859-15. + self._create_unicode_name(u"???/?") + + tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1", + errors="utf-8") + self.assertEqual(tar.getnames()[0], "???/" + u"?".encode("utf8")) + + +class AppendTest(unittest.TestCase): + # Test append mode (cp. patch #1652681). + + def setUp(self): + test_support.gc_collect() + self.tarname = tmpname + if os.path.exists(self.tarname): + os.remove(self.tarname) + + def _add_testfile(self, fileobj=None): + tar = tarfile.open(self.tarname, "a", fileobj=fileobj) + tar.addfile(tarfile.TarInfo("bar")) + tar.close() + + def _create_testtar(self, mode="w:"): + src = tarfile.open(tarname, encoding="iso8859-1") + t = src.getmember("ustar/regtype") + t.name = "foo" + f = src.extractfile(t) + tar = tarfile.open(self.tarname, mode) + tar.addfile(t, f) + tar.close() + + def _test(self, names=["bar"], fileobj=None): + tar = tarfile.open(self.tarname, fileobj=fileobj) + self.assertEqual(tar.getnames(), names) + + def test_non_existing(self): + self._add_testfile() + self._test() + + def test_empty(self): + tarfile.open(self.tarname, "w:").close() + self._add_testfile() + self._test() + + def test_empty_fileobj(self): + fobj = StringIO.StringIO("\0" * 1024) + self._add_testfile(fobj) + fobj.seek(0) + self._test(fileobj=fobj) + + def test_fileobj(self): + self._create_testtar() + data = open(self.tarname).read() + fobj = StringIO.StringIO(data) + self._add_testfile(fobj) + fobj.seek(0) + self._test(names=["foo", "bar"], fileobj=fobj) + + def test_existing(self): + self._create_testtar() + self._add_testfile() + self._test(names=["foo", "bar"]) + + def test_append_gz(self): + if gzip is None: + return + self._create_testtar("w:gz") + self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a") + + def test_append_bz2(self): + if bz2 is None: + return + self._create_testtar("w:bz2") + self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a") + + # Append mode is supposed to fail if the tarfile to append to + # does not end with a zero block. + def _test_error(self, data): + open(self.tarname, "wb").write(data) + self.assertRaises(tarfile.ReadError, self._add_testfile) + + def test_null(self): + self._test_error("") + + def test_incomplete(self): + self._test_error("\0" * 13) + + def test_premature_eof(self): + data = tarfile.TarInfo("foo").tobuf() + self._test_error(data) + + def test_trailing_garbage(self): + data = tarfile.TarInfo("foo").tobuf() + self._test_error(data + "\0" * 13) + + def test_invalid(self): + self._test_error("a" * 512) + + +class LimitsTest(unittest.TestCase): + + def test_ustar_limits(self): + # 100 char name + tarinfo = tarfile.TarInfo("0123456789" * 10) + tarinfo.tobuf(tarfile.USTAR_FORMAT) + + # 101 char name that cannot be stored + tarinfo = tarfile.TarInfo("0123456789" * 10 + "0") + self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) + + # 256 char name with a slash at pos 156 + tarinfo = tarfile.TarInfo("123/" * 62 + "longname") + tarinfo.tobuf(tarfile.USTAR_FORMAT) + + # 256 char name that cannot be stored + tarinfo = tarfile.TarInfo("1234567/" * 31 + "longname") + self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) + + # 512 char name + tarinfo = tarfile.TarInfo("123/" * 126 + "longname") + self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) + + # 512 char linkname + tarinfo = tarfile.TarInfo("longlink") + tarinfo.linkname = "123/" * 126 + "longname" + self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) + + # uid > 8 digits + tarinfo = tarfile.TarInfo("name") + tarinfo.uid = 010000000 + self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) + + def test_gnu_limits(self): + tarinfo = tarfile.TarInfo("123/" * 126 + "longname") + tarinfo.tobuf(tarfile.GNU_FORMAT) + + tarinfo = tarfile.TarInfo("longlink") + tarinfo.linkname = "123/" * 126 + "longname" + tarinfo.tobuf(tarfile.GNU_FORMAT) + + # uid >= 256 ** 7 + tarinfo = tarfile.TarInfo("name") + tarinfo.uid = 04000000000000000000L + self.assertRaises(ValueError, tarinfo.tobuf, tarfile.GNU_FORMAT) + + def test_pax_limits(self): + tarinfo = tarfile.TarInfo("123/" * 126 + "longname") + tarinfo.tobuf(tarfile.PAX_FORMAT) + + tarinfo = tarfile.TarInfo("longlink") + tarinfo.linkname = "123/" * 126 + "longname" + tarinfo.tobuf(tarfile.PAX_FORMAT) + + tarinfo = tarfile.TarInfo("name") + tarinfo.uid = 04000000000000000000L + tarinfo.tobuf(tarfile.PAX_FORMAT) + + +class ContextManagerTest(unittest.TestCase): + + def test_basic(self): + with tarfile.open(tarname) as tar: + self.assertFalse(tar.closed, "closed inside runtime context") + self.assertTrue(tar.closed, "context manager failed") + + def test_closed(self): + # The __enter__() method is supposed to raise IOError + # if the TarFile object is already closed. + tar = tarfile.open(tarname) + tar.close() + with self.assertRaises(IOError): + with tar: + pass + + def test_exception(self): + # Test if the IOError exception is passed through properly. + with self.assertRaises(Exception) as exc: + with tarfile.open(tarname) as tar: + raise IOError + self.assertIsInstance(exc.exception, IOError, + "wrong exception raised in context manager") + self.assertTrue(tar.closed, "context manager failed") + + def test_no_eof(self): + # __exit__() must not write end-of-archive blocks if an + # exception was raised. + try: + with tarfile.open(tmpname, "w") as tar: + raise Exception + except: + pass + self.assertEqual(os.path.getsize(tmpname), 0, + "context manager wrote an end-of-archive block") + self.assertTrue(tar.closed, "context manager failed") + + def test_eof(self): + # __exit__() must write end-of-archive blocks, i.e. call + # TarFile.close() if there was no error. + with tarfile.open(tmpname, "w"): + pass + self.assertNotEqual(os.path.getsize(tmpname), 0, + "context manager wrote no end-of-archive block") + + def test_fileobj(self): + # Test that __exit__() did not close the external file + # object. + fobj = open(tmpname, "wb") + try: + with tarfile.open(fileobj=fobj, mode="w") as tar: + raise Exception + except: + pass + self.assertFalse(fobj.closed, "external file object was closed") + self.assertTrue(tar.closed, "context manager failed") + fobj.close() + + +class LinkEmulationTest(ReadTest): + + # Test for issue #8741 regression. On platforms that do not support + # symbolic or hard links tarfile tries to extract these types of members as + # the regular files they point to. + def _test_link_extraction(self, name): + self.tar.extract(name, TEMPDIR) + data = open(os.path.join(TEMPDIR, name), "rb").read() + self.assertEqual(md5sum(data), md5_regtype) + + def test_hardlink_extraction1(self): + self._test_link_extraction("ustar/lnktype") + + def test_hardlink_extraction2(self): + self._test_link_extraction("./ustar/linktest2/lnktype") + + def test_symlink_extraction1(self): + self._test_link_extraction("ustar/symtype") + + def test_symlink_extraction2(self): + self._test_link_extraction("./ustar/linktest2/symtype") + + +class GzipMiscReadTest(MiscReadTest): + tarname = gzipname + mode = "r:gz" +class GzipUstarReadTest(UstarReadTest): + tarname = gzipname + mode = "r:gz" +class GzipStreamReadTest(StreamReadTest): + tarname = gzipname + mode = "r|gz" +class GzipWriteTest(WriteTest): + mode = "w:gz" +class GzipStreamWriteTest(StreamWriteTest): + mode = "w|gz" + + +class Bz2MiscReadTest(MiscReadTest): + tarname = bz2name + mode = "r:bz2" +class Bz2UstarReadTest(UstarReadTest): + tarname = bz2name + mode = "r:bz2" +class Bz2StreamReadTest(StreamReadTest): + tarname = bz2name + mode = "r|bz2" +class Bz2WriteTest(WriteTest): + mode = "w:bz2" +class Bz2StreamWriteTest(StreamWriteTest): + mode = "w|bz2" + +class Bz2PartialReadTest(unittest.TestCase): + # Issue5068: The _BZ2Proxy.read() method loops forever + # on an empty or partial bzipped file. + + def _test_partial_input(self, mode): + class MyStringIO(StringIO.StringIO): + hit_eof = False + def read(self, n): + if self.hit_eof: + raise AssertionError("infinite loop detected in tarfile.open()") + self.hit_eof = self.pos == self.len + return StringIO.StringIO.read(self, n) + def seek(self, *args): + self.hit_eof = False + return StringIO.StringIO.seek(self, *args) + + data = bz2.compress(tarfile.TarInfo("foo").tobuf()) + for x in range(len(data) + 1): + try: + tarfile.open(fileobj=MyStringIO(data[:x]), mode=mode) + except tarfile.ReadError: + pass # we have no interest in ReadErrors + + def test_partial_input(self): + self._test_partial_input("r") + + def test_partial_input_bz2(self): + self._test_partial_input("r:bz2") + + +def test_main(): + os.makedirs(TEMPDIR) + + tests = [ + UstarReadTest, + MiscReadTest, + StreamReadTest, + DetectReadTest, + MemberReadTest, + GNUReadTest, + PaxReadTest, + WriteTest, + StreamWriteTest, + GNUWriteTest, + PaxWriteTest, + UstarUnicodeTest, + GNUUnicodeTest, + PaxUnicodeTest, + AppendTest, + LimitsTest, + ContextManagerTest, + ] + + if hasattr(os, "link"): + tests.append(HardlinkTest) + else: + tests.append(LinkEmulationTest) + + fobj = open(tarname, "rb") + data = fobj.read() + fobj.close() + + if gzip: + # Create testtar.tar.gz and add gzip-specific tests. + tar = gzip.open(gzipname, "wb") + tar.write(data) + tar.close() + + tests += [ + GzipMiscReadTest, + GzipUstarReadTest, + GzipStreamReadTest, + GzipWriteTest, + GzipStreamWriteTest, + ] + + if bz2: + # Create testtar.tar.bz2 and add bz2-specific tests. + tar = bz2.BZ2File(bz2name, "wb") + tar.write(data) + tar.close() + + tests += [ + Bz2MiscReadTest, + Bz2UstarReadTest, + Bz2StreamReadTest, + Bz2WriteTest, + Bz2StreamWriteTest, + Bz2PartialReadTest, + ] + + try: + test_support.run_unittest(*tests) + finally: + if os.path.exists(TEMPDIR): + shutil.rmtree(TEMPDIR) + +if __name__ == "__main__": + test_main() -- Repository URL: https://hg.python.org/jython