Skip to content

Commit c52f2f8

Browse files
committed
[GR-10449] Math.atan2 is not fully implemented.
1 parent aa64dad commit c52f2f8

File tree

2 files changed

+137
-3
lines changed

2 files changed

+137
-3
lines changed

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

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,76 @@ class MyNumber():
572572
def __float__(self):
573573
return -2.;
574574
self.ftest('MyFloat()**-3.', math.pow(MyNumber(), -3.0), -0.125)
575-
575+
576+
def testAtan2(self):
577+
self.assertRaises(TypeError, math.atan2)
578+
self.ftest('atan2(-1, 0)', math.atan2(-1, 0), -math.pi/2)
579+
self.ftest('atan2(-1, 1)', math.atan2(-1, 1), -math.pi/4)
580+
self.ftest('atan2(0, 1)', math.atan2(0, 1), 0)
581+
self.ftest('atan2(1, 1)', math.atan2(1, 1), math.pi/4)
582+
self.ftest('atan2(1, 0)', math.atan2(1, 0), math.pi/2)
583+
584+
# math.atan2(0, x)
585+
self.ftest('atan2(0., -inf)', math.atan2(0., NINF), math.pi)
586+
self.ftest('atan2(0., -2.3)', math.atan2(0., -2.3), math.pi)
587+
self.ftest('atan2(0., -0.)', math.atan2(0., -0.), math.pi)
588+
self.assertEqual(math.atan2(0., 0.), 0.)
589+
self.assertEqual(math.atan2(0., 2.3), 0.)
590+
self.assertEqual(math.atan2(0., INF), 0.)
591+
self.assertTrue(math.isnan(math.atan2(0., NAN)))
592+
# math.atan2(-0, x)
593+
self.ftest('atan2(-0., -inf)', math.atan2(-0., NINF), -math.pi)
594+
self.ftest('atan2(-0., -2.3)', math.atan2(-0., -2.3), -math.pi)
595+
self.ftest('atan2(-0., -0.)', math.atan2(-0., -0.), -math.pi)
596+
self.assertEqual(math.atan2(-0., 0.), -0.)
597+
self.assertEqual(math.atan2(-0., 2.3), -0.)
598+
self.assertEqual(math.atan2(-0., INF), -0.)
599+
self.assertTrue(math.isnan(math.atan2(-0., NAN)))
600+
# math.atan2(INF, x)
601+
self.ftest('atan2(inf, -inf)', math.atan2(INF, NINF), math.pi*3/4)
602+
self.ftest('atan2(inf, -2.3)', math.atan2(INF, -2.3), math.pi/2)
603+
self.ftest('atan2(inf, -0.)', math.atan2(INF, -0.0), math.pi/2)
604+
self.ftest('atan2(inf, 0.)', math.atan2(INF, 0.0), math.pi/2)
605+
self.ftest('atan2(inf, 2.3)', math.atan2(INF, 2.3), math.pi/2)
606+
self.ftest('atan2(inf, inf)', math.atan2(INF, INF), math.pi/4)
607+
self.assertTrue(math.isnan(math.atan2(INF, NAN)))
608+
# math.atan2(NINF, x)
609+
self.ftest('atan2(-inf, -inf)', math.atan2(NINF, NINF), -math.pi*3/4)
610+
self.ftest('atan2(-inf, -2.3)', math.atan2(NINF, -2.3), -math.pi/2)
611+
self.ftest('atan2(-inf, -0.)', math.atan2(NINF, -0.0), -math.pi/2)
612+
self.ftest('atan2(-inf, 0.)', math.atan2(NINF, 0.0), -math.pi/2)
613+
self.ftest('atan2(-inf, 2.3)', math.atan2(NINF, 2.3), -math.pi/2)
614+
self.ftest('atan2(-inf, inf)', math.atan2(NINF, INF), -math.pi/4)
615+
self.assertTrue(math.isnan(math.atan2(NINF, NAN)))
616+
# math.atan2(+finite, x)
617+
self.ftest('atan2(2.3, -inf)', math.atan2(2.3, NINF), math.pi)
618+
self.ftest('atan2(2.3, -0.)', math.atan2(2.3, -0.), math.pi/2)
619+
self.ftest('atan2(2.3, 0.)', math.atan2(2.3, 0.), math.pi/2)
620+
self.assertEqual(math.atan2(2.3, INF), 0.)
621+
self.assertTrue(math.isnan(math.atan2(2.3, NAN)))
622+
# math.atan2(-finite, x)
623+
self.ftest('atan2(-2.3, -inf)', math.atan2(-2.3, NINF), -math.pi)
624+
self.ftest('atan2(-2.3, -0.)', math.atan2(-2.3, -0.), -math.pi/2)
625+
self.ftest('atan2(-2.3, 0.)', math.atan2(-2.3, 0.), -math.pi/2)
626+
self.assertEqual(math.atan2(-2.3, INF), -0.)
627+
self.assertTrue(math.isnan(math.atan2(-2.3, NAN)))
628+
# math.atan2(NAN, x)
629+
self.assertTrue(math.isnan(math.atan2(NAN, NINF)))
630+
self.assertTrue(math.isnan(math.atan2(NAN, -2.3)))
631+
self.assertTrue(math.isnan(math.atan2(NAN, -0.)))
632+
self.assertTrue(math.isnan(math.atan2(NAN, 0.)))
633+
self.assertTrue(math.isnan(math.atan2(NAN, 2.3)))
634+
self.assertTrue(math.isnan(math.atan2(NAN, INF)))
635+
self.assertTrue(math.isnan(math.atan2(NAN, NAN)))
636+
637+
# Testing specializations
638+
self.ftest('atan2(0.5,1)', math.atan2(0.5,1), 0.4636476090008061)
639+
self.ftest('atan2(1,0.5)', math.atan2(1,0.5), 1.1071487177940904)
640+
self.ftest('atan2(BIG_INT,BIG_INT)', math.atan2(BIG_INT,BIG_INT), 0.7853981633974483)
641+
self.ftest('atan2(BIG_INT,1)', math.atan2(BIG_INT,1), 1.5707963267948966)
642+
self.ftest('atan2(BIG_INT,0.1)', math.atan2(BIG_INT,0.1), 1.5707963267948966)
643+
self.ftest('atan2(MyFloat(),MyFloat())', math.atan2(MyFloat(),MyFloat()), 0.7853981633974483)
644+
self.ftest('atan2(BIG_INT,MyFloat())', math.atan2(BIG_INT,MyFloat()), 1.5707963267948966)
576645

577646
def test_fabs(self):
578647
self.assertEqual(math.fabs(-1), 1)

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

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,12 +1547,77 @@ Object trunc(Object obj,
15471547
}
15481548

15491549
@Builtin(name = "atan2", fixedNumOfArguments = 2)
1550+
@TypeSystemReference(PythonArithmeticTypes.class)
1551+
@ImportStatic(MathGuards.class)
15501552
@GenerateNodeFactory
1551-
public abstract static class Atan2Node extends PythonBuiltinNode {
1553+
public abstract static class Atan2Node extends PythonBinaryBuiltinNode {
1554+
1555+
public abstract double executeObject(Object left, Object right);
1556+
1557+
@Specialization
1558+
double atan2(long left, long right) {
1559+
return atan2DD((double) left, (double) right);
1560+
}
1561+
1562+
@Specialization
1563+
double atan2(long left, double right) {
1564+
return atan2DD((double) left, right);
1565+
}
1566+
1567+
@Specialization
1568+
double atan2(double left, long right) {
1569+
return atan2DD(left, (double) right);
1570+
}
1571+
1572+
@Specialization
1573+
double atan2(PInt left, PInt right) {
1574+
return atan2DD(left.doubleValue(), right.doubleValue());
1575+
}
1576+
1577+
@Specialization
1578+
double atan2(PInt left, long right) {
1579+
return atan2DD(left.doubleValue(), (double) right);
1580+
}
1581+
1582+
@Specialization
1583+
double atan2(PInt left, double right) {
1584+
return atan2DD(left.doubleValue(), right);
1585+
}
15521586

15531587
@Specialization
1554-
double atan2(double left, double right) {
1588+
double atan2(long left, PInt right) {
1589+
return atan2DD((double) left, right.doubleValue());
1590+
}
1591+
1592+
@Specialization
1593+
double atan2(double left, PInt right) {
1594+
return atan2DD(left, right.doubleValue());
1595+
}
1596+
1597+
@Specialization
1598+
double atan2DD(double left, double right) {
15551599
return Math.atan2(left, right);
15561600
}
1601+
1602+
@Specialization(guards = "!isNumber(left) || !isNumber(right)")
1603+
double atan2(Object left, Object right,
1604+
@Cached("create(__FLOAT__)") LookupAndCallUnaryNode dispatchLeftFloat,
1605+
@Cached("create(__FLOAT__)") LookupAndCallUnaryNode dispatchRightFloat,
1606+
@Cached("create()") Atan2Node recursiveNode) {
1607+
Object leftFloat = dispatchLeftFloat.executeObject(left);
1608+
if (leftFloat == PNone.NO_VALUE) {
1609+
throw raise(TypeError, "must be real number, not %p", left);
1610+
}
1611+
Object rightFloat = dispatchLeftFloat.executeObject(right);
1612+
if (leftFloat == PNone.NO_VALUE) {
1613+
throw raise(TypeError, "must be real number, not %p", right);
1614+
}
1615+
1616+
return recursiveNode.executeObject(leftFloat, rightFloat);
1617+
}
1618+
1619+
protected Atan2Node create() {
1620+
return MathModuleBuiltinsFactory.Atan2NodeFactory.create(new PNode[0]);
1621+
}
15571622
}
15581623
}

0 commit comments

Comments
 (0)