Skip to content

Commit 9ec8b61

Browse files
committed
Use PyNumber_Index in the non-float branch of math_factorial and add deprecation warning for floats
1 parent 3fe3304 commit 9ec8b61

2 files changed

Lines changed: 35 additions & 15 deletions

File tree

Lib/test/test_math.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from test.support import run_unittest, verbose, requires_IEEE_754
55
from test import support
66
import unittest
7+
import decimal
78
import math
89
import os
910
import platform
@@ -494,26 +495,33 @@ def testFabs(self):
494495

495496
def testFactorial(self):
496497
self.assertEqual(math.factorial(0), 1)
497-
self.assertEqual(math.factorial(0.0), 1)
498-
total = 1
499-
for i in range(1, 1000):
500-
total *= i
501-
self.assertEqual(math.factorial(i), total)
502-
self.assertEqual(math.factorial(float(i)), total)
503-
self.assertEqual(math.factorial(i), py_factorial(i))
498+
with self.assertWarns(DeprecationWarning):
499+
self.assertEqual(math.factorial(0.0), 1)
500+
total = 1
501+
for i in range(1, 1000):
502+
total *= i
503+
self.assertEqual(math.factorial(i), total)
504+
self.assertEqual(math.factorial(float(i)), total)
505+
self.assertEqual(math.factorial(i), py_factorial(i))
504506
self.assertRaises(ValueError, math.factorial, -1)
505-
self.assertRaises(ValueError, math.factorial, -1.0)
506-
self.assertRaises(ValueError, math.factorial, -10**100)
507-
self.assertRaises(ValueError, math.factorial, -1e100)
508-
self.assertRaises(ValueError, math.factorial, math.pi)
507+
with self.assertWarns(DeprecationWarning):
508+
self.assertRaises(ValueError, math.factorial, -1.0)
509+
self.assertRaises(ValueError, math.factorial, -10**100)
510+
self.assertRaises(ValueError, math.factorial, -1e100)
511+
self.assertRaises(ValueError, math.factorial, math.pi)
512+
513+
def testFactorialNonIntegers(self):
514+
self.assertRaises(TypeError, math.factorial, decimal.Decimal(5.2))
515+
self.assertRaises(TypeError, math.factorial, "5")
509516

510517
# Other implementations may place different upper bounds.
511518
@support.cpython_only
512519
def testFactorialHugeInputs(self):
513520
# Currently raises ValueError for inputs that are too large
514521
# to fit into a C long.
515522
self.assertRaises(OverflowError, math.factorial, 10**100)
516-
self.assertRaises(OverflowError, math.factorial, 1e100)
523+
with self.assertWarns(DeprecationWarning):
524+
self.assertRaises(OverflowError, math.factorial, 1e100)
517525

518526
def testFloor(self):
519527
self.assertRaises(TypeError, math.floor)

Modules/mathmodule.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,7 +1656,7 @@ math_factorial(PyObject *module, PyObject *arg)
16561656
{
16571657
long x;
16581658
int overflow;
1659-
PyObject *result, *odd_part, *two_valuation;
1659+
PyObject *result, *odd_part, *two_valuation, *pyint_form;
16601660

16611661
if (PyFloat_Check(arg)) {
16621662
PyObject *lx;
@@ -1671,9 +1671,21 @@ math_factorial(PyObject *module, PyObject *arg)
16711671
return NULL;
16721672
x = PyLong_AsLongAndOverflow(lx, &overflow);
16731673
Py_DECREF(lx);
1674+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
1675+
"Passing float instances to math.factorial will be "
1676+
"removed in future versions.", 1) < 0) {
1677+
return NULL;
1678+
}
1679+
1680+
}
1681+
else{
1682+
pyint_form = PyNumber_Index(arg);
1683+
if( pyint_form == NULL){
1684+
return NULL;
1685+
}
1686+
x = PyLong_AsLongAndOverflow(pyint_form, &overflow);
1687+
Py_DECREF(pyint_form);
16741688
}
1675-
else
1676-
x = PyLong_AsLongAndOverflow(arg, &overflow);
16771689

16781690
if (x == -1 && PyErr_Occurred()) {
16791691
return NULL;

0 commit comments

Comments
 (0)