Skip to content

Commit 52664d8

Browse files
committed
[GR-10722] Not all functions from Math module are implemented correctly.
PullRequest: graalpython/103
2 parents e076916 + e1bac72 commit 52664d8

File tree

5 files changed

+386
-55
lines changed

5 files changed

+386
-55
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_math.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ class MyFloat:
159159
def __float__(self):
160160
return 0.6
161161

162+
class MyInt(object):
163+
def __init__(self, value):
164+
self.value = value
165+
def __int__(self):
166+
return self.value
167+
162168
class MathTests(unittest.TestCase):
163169

164170
def ftest(self, name, got, expected, ulp_tol=5, abs_tol=0.0):
@@ -482,6 +488,11 @@ def test_basic_copysign(self):
482488
self.assertEqual(math.copysign(999999999999999999999.1, 1), 999999999999999999999.1)
483489
self.assertRaises(TypeError, math.copysign, 'hello', 1)
484490
self.assertRaises(TypeError, math.copysign, 1, 'hello')
491+
492+
self.assertEqual(math.copysign(MyFloat(), 1), 0.6)
493+
self.assertEqual(math.copysign(MyFloat(), -1), -0.6)
494+
self.assertEqual(math.copysign(1.2, MyFloat()), 1.2)
495+
self.assertEqual(math.copysign(MyFloat(), MyFloat()), 0.6)
485496

486497
def test_inf_copysign(self):
487498
self.assertEqual(math.copysign(1.0, float('inf')), 1.0)
@@ -928,6 +939,8 @@ def test_fabs(self):
928939
self.assertEqual(math.fabs(True), 1.0)
929940
self.assertEqual(math.fabs(False), 0.0)
930941

942+
self.assertEqual(math.fabs(MyFloat()), 0.6)
943+
931944
def test_factorial(self):
932945
self.assertRaises(ValueError, math.factorial, float('nan'))
933946
self.assertRaises(ValueError, math.factorial, float('inf'))
@@ -953,6 +966,12 @@ def test_factorial(self):
953966
self.assertEqual(math.factorial(13), 6227020800)
954967
self.assertEqual(math.factorial(30), 265252859812191058636308480000000)
955968
self.assertRaises(ValueError, math.factorial, -11.1)
969+
970+
self.assertEqual(math.factorial(MyInt(4)), 24)
971+
self.assertEqual(math.factorial(MyInt(True)), 1)
972+
self.assertRaises(TypeError, math.factorial, MyIndexable(4))
973+
self.assertRaises(TypeError, math.factorial, MyFloat())
974+
self.assertRaises(TypeError, math.factorial, MyInt(0.6))
956975

957976
def testGcd(self):
958977
if (sys.version_info.major >= 3 and sys.version_info.minor >= 5):
@@ -1038,6 +1057,15 @@ class TestNoFloor:
10381057
self.assertEqual(math.floor(2432902008176640000999), 2432902008176640000999)
10391058
self.assertEqual(math.floor(2432902008176640000999.99), 2432902008176640000999.99)
10401059

1060+
self.assertEqual(math.floor(MyFloat()), 0)
1061+
1062+
class MyFloorFloat():
1063+
def __floor__(self):
1064+
return 12
1065+
def __float(self):
1066+
return 112
1067+
self.assertEqual(math.floor(MyFloorFloat()), 12)
1068+
10411069
def test_fmod(self):
10421070
self.assertRaises(TypeError, math.fmod)
10431071
self.ftest('fmod(10, 1)', math.fmod(10, 1), 0.0)
@@ -1103,6 +1131,9 @@ def test_fmod(self):
11031131
self.assertEqual(math.fmod(2432902008176640000999, 12.12), 10.396369527944033)
11041132
self.assertEqual(math.fmod(-1e-100, 1e100), -1e-100)
11051133

1134+
self.assertEqual(math.fmod(MyFloat(), 1), 0.6)
1135+
self.assertEqual(math.fmod(MyFloat(), MyFloat()), 0.)
1136+
11061137
def testExp(self):
11071138
self.assertRaises(TypeError, math.exp)
11081139
self.ftest('exp(-1)', math.exp(-1), 1/math.e)
@@ -1174,6 +1205,7 @@ def getY():
11741205
testfrexp('frexp(Y(11.11))', math.frexp(Y(11.11)), (0.694375, 4))
11751206
testfrexp('frexp(2**1023)', math.frexp(2**1023), (0.5, 1024))
11761207
self.assertRaises(OverflowError, math.frexp, 2**1024)
1208+
testfrexp('frexp(MyFloat())', math.frexp(MyFloat()), (0.6, 0))
11771209

11781210
def test_ldexp(self):
11791211
self.assertRaises(TypeError, math.ldexp)
@@ -1223,6 +1255,13 @@ class II(int):
12231255
self.assertRaises(TypeError, math.ldexp, 1, 'Hello')
12241256
self.assertEqual(math.ldexp(7589167167882033, -48), 26.962138008038156)
12251257

1258+
self.assertRaises(TypeError, math.ldexp, 1, MyIndexable(2))
1259+
self.assertRaises(TypeError, math.ldexp, 1, MyInt(2))
1260+
self.assertRaises(TypeError, math.ldexp, 1, MyFloat())
1261+
self.assertEqual(math.ldexp(0.1, True), 0.2)
1262+
self.assertEqual(math.ldexp(MyFloat(),True), 1.2)
1263+
self.assertRaises(TypeError, math.ldexp, MyInt(2), MyFloat())
1264+
12261265
def test_trunc(self):
12271266
self.assertEqual(math.trunc(1), 1)
12281267
self.assertEqual(math.trunc(-1), -1)
@@ -1595,3 +1634,142 @@ def msum(iterable):
15951634

15961635
self.assertRaises(ValueError, math.fsum, [1., 2, INF, NINF])
15971636
self.assertEqual(math.fsum([1., 2, INF, INF]), INF)
1637+
1638+
if (sys.version_info.major >= 3 and sys.version_info.minor >= 5):
1639+
# math.isclose since 3.5
1640+
class IsCloseTests(unittest.TestCase):
1641+
isclose = staticmethod(math.isclose) # sublcasses should override this
1642+
1643+
def assertIsClose(self, a, b, *args, **kwargs):
1644+
self.assertTrue(self.isclose(a, b, *args, **kwargs),
1645+
msg="%s and %s should be close!" % (a, b))
1646+
1647+
def assertIsNotClose(self, a, b, *args, **kwargs):
1648+
self.assertFalse(self.isclose(a, b, *args, **kwargs),
1649+
msg="%s and %s should not be close!" % (a, b))
1650+
1651+
def assertAllClose(self, examples, *args, **kwargs):
1652+
for a, b in examples:
1653+
self.assertIsClose(a, b, *args, **kwargs)
1654+
1655+
def assertAllNotClose(self, examples, *args, **kwargs):
1656+
for a, b in examples:
1657+
self.assertIsNotClose(a, b, *args, **kwargs)
1658+
1659+
def test_negative_tolerances(self):
1660+
# ValueError should be raised if either tolerance is less than zero
1661+
with self.assertRaises(ValueError):
1662+
self.assertIsClose(1, 1, rel_tol=-1e-100)
1663+
with self.assertRaises(ValueError):
1664+
self.assertIsClose(1, 1, rel_tol=1e-100, abs_tol=-1e10)
1665+
1666+
def test_identical(self):
1667+
# identical values must test as close
1668+
identical_examples = [(2.0, 2.0),
1669+
(0.1e200, 0.1e200),
1670+
(1.123e-300, 1.123e-300),
1671+
(12345, 12345.0),
1672+
(0.0, -0.0),
1673+
(345678, 345678)]
1674+
self.assertAllClose(identical_examples, rel_tol=0.0, abs_tol=0.0)
1675+
1676+
def test_eight_decimal_places(self):
1677+
# examples that are close to 1e-8, but not 1e-9
1678+
eight_decimal_places_examples = [(1e8, 1e8 + 1),
1679+
(-1e-8, -1.000000009e-8),
1680+
(1.12345678, 1.12345679)]
1681+
self.assertAllClose(eight_decimal_places_examples, rel_tol=1e-8)
1682+
self.assertAllNotClose(eight_decimal_places_examples, rel_tol=1e-9)
1683+
1684+
def test_near_zero(self):
1685+
# values close to zero
1686+
near_zero_examples = [(1e-9, 0.0),
1687+
(-1e-9, 0.0),
1688+
(-1e-150, 0.0)]
1689+
# these should not be close to any rel_tol
1690+
self.assertAllNotClose(near_zero_examples, rel_tol=0.9)
1691+
# these should be close to abs_tol=1e-8
1692+
self.assertAllClose(near_zero_examples, abs_tol=1e-8)
1693+
1694+
def test_identical_infinite(self):
1695+
# these are close regardless of tolerance -- i.e. they are equal
1696+
self.assertIsClose(INF, INF)
1697+
self.assertIsClose(INF, INF, abs_tol=0.0)
1698+
self.assertIsClose(NINF, NINF)
1699+
self.assertIsClose(NINF, NINF, abs_tol=0.0)
1700+
1701+
def test_inf_ninf_nan(self):
1702+
# these should never be close (following IEEE 754 rules for equality)
1703+
not_close_examples = [(NAN, NAN),
1704+
(NAN, 1e-100),
1705+
(1e-100, NAN),
1706+
(INF, NAN),
1707+
(NAN, INF),
1708+
(INF, NINF),
1709+
(INF, 1.0),
1710+
(1.0, INF),
1711+
(INF, 1e308),
1712+
(1e308, INF)]
1713+
# use largest reasonable tolerance
1714+
self.assertAllNotClose(not_close_examples, abs_tol=0.999999999999999)
1715+
1716+
def test_zero_tolerance(self):
1717+
# test with zero tolerance
1718+
zero_tolerance_close_examples = [(1.0, 1.0),
1719+
(-3.4, -3.4),
1720+
(-1e-300, -1e-300)]
1721+
self.assertAllClose(zero_tolerance_close_examples, rel_tol=0.0)
1722+
1723+
zero_tolerance_not_close_examples = [(1.0, 1.000000000000001),
1724+
(0.99999999999999, 1.0),
1725+
(1.0e200, .999999999999999e200)]
1726+
self.assertAllNotClose(zero_tolerance_not_close_examples, rel_tol=0.0)
1727+
1728+
def test_asymmetry(self):
1729+
# test the asymmetry example from PEP 485
1730+
self.assertAllClose([(9, 10), (10, 9)], rel_tol=0.1)
1731+
1732+
def test_integers(self):
1733+
# test with integer values
1734+
integer_examples = [(100000001, 100000000),
1735+
(123456789, 123456788)]
1736+
1737+
self.assertAllClose(integer_examples, rel_tol=1e-8)
1738+
self.assertAllNotClose(integer_examples, rel_tol=1e-9)
1739+
1740+
# TODO the test is commented out due to GR-10712
1741+
'''
1742+
def test_decimals(self):
1743+
# test with Decimal values
1744+
from decimal import Decimal#
1745+
1746+
decimal_examples = [(Decimal('1.00000001'), Decimal('1.0')),
1747+
(Decimal('1.00000001e-20'), Decimal('1.0e-20')),
1748+
(Decimal('1.00000001e-100'), Decimal('1.0e-100')),
1749+
(Decimal('1.00000001e20'), Decimal('1.0e20'))]
1750+
self.assertAllClose(decimal_examples, rel_tol=1e-8)
1751+
self.assertAllNotClose(decimal_examples, rel_tol=1e-9)
1752+
'''
1753+
1754+
# TODO the test is commented out due to GR-10711
1755+
'''
1756+
def test_fractions(self):
1757+
# test with Fraction values
1758+
from fractions import Fraction
1759+
1760+
fraction_examples = [
1761+
(Fraction(1, 100000000) + 1, Fraction(1)),
1762+
(Fraction(100000001), Fraction(100000000)),
1763+
(Fraction(10**8 + 1, 10**28), Fraction(1, 10**20))]
1764+
self.assertAllClose(fraction_examples, rel_tol=1e-8)
1765+
self.assertAllNotClose(fraction_examples, rel_tol=1e-9)
1766+
'''
1767+
def test_objects(self):
1768+
# these are close regardless of tolerance -- i.e. they are equal
1769+
self.assertIsClose(MyFloat(), MyFloat())
1770+
self.assertIsClose(MyFloat(), MyFloat(), abs_tol=0.0)
1771+
self.assertIsClose(MyFloat(), MyFloat(), abs_tol=MyFloat())
1772+
self.assertIsClose(MyFloat(), MyFloat(), rel_tol=0.0)
1773+
self.assertIsClose(MyFloat(), MyFloat(), rel_tol=MyFloat())
1774+
1775+
self.assertIsNotClose(MyFloat(), 10)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
import com.oracle.graal.python.nodes.object.GetClassNode;
120120
import com.oracle.graal.python.nodes.subscript.GetItemNode;
121121
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
122-
import com.oracle.graal.python.nodes.util.CastToIntNode;
122+
import com.oracle.graal.python.nodes.util.CastToIntegerFromIndexNode;
123123
import com.oracle.graal.python.runtime.PythonContext;
124124
import com.oracle.graal.python.runtime.PythonCore;
125125
import com.oracle.graal.python.runtime.PythonOptions;
@@ -235,7 +235,7 @@ public String doPI(PInt x) {
235235

236236
@Specialization
237237
public String doO(Object x,
238-
@Cached("create()") CastToIntNode toIntNode,
238+
@Cached("create()") CastToIntegerFromIndexNode toIntNode,
239239
@Cached("create()") BinNode recursiveNode) {
240240
Object value = toIntNode.execute(x);
241241
return recursiveNode.executeObject(value);

0 commit comments

Comments
 (0)