special.factorial accepting floats

The docstring for special.factorial says that the function accepts ints, and int arrays. However, it also seems to accept float arrays (including those that contain np.nan). Is there a rationale for it accepting floats/float arrays? One can't calculate factorials of non-integers.

On Thu, Apr 30, 2020 at 9:45 PM Andrew Nelson <andyfaff@gmail.com> wrote:
The docstring for special.factorial says that the function accepts ints, and int arrays. However, it also seems to accept float arrays (including those that contain np.nan).
Is there a rationale for it accepting floats/float arrays? One can't calculate factorials of non-integers.
When `exact=False`, the default, the result is computed with a gamma function, which generalizes the factorial function to non-integers. The answer that you get is a perfectly reasonable, meaningful, non-arbitrary result. When `exact=True`, you will see a `ValueError`, because we defer computation over to `math.factorial()` which does check for integralness because it's doing an exact computation that requires integralness. I guess that we could add in a check for integralness in the `exact=False` case, but to what end? Would we catch anyone's real errors? There's actually a possible use case here for representing integral data that have missing data represented as NaNs (i.e. a float array where all the non-NaN entries are integral-valued despite being floating point numbers). -- Robert Kern

I came across this because I was setting up a CI run against Python3.9. On Py3.9 there is a DeprecationWarning if `math.factorial` is supplied a float: On Py3.8: math.factorial(2.0) --> 2 On Py3.9: math.factorial(2.0) --> 2 and emits a "DeprecationWarning: Using factorial() with floats is deprecated" Presumably with Py >> 3.9: math.factorial(2.0) will raise an Exception As you say, `math.factorial` is used by `special.factorial` for `exact=True`. When Python3.9 is released various tests will start to fail because of that DeprecationWarning. I know it's early days, I'm just trying to be proactive. - how to modify tests to account for that DeprecationWarning when `special.factorial` is supplied a float with `exact=True` - how test code and special.factorial code has to be modified for a post DeprecationWarning period.

On Thu, Apr 30, 2020 at 11:36 PM Andrew Nelson <andyfaff@gmail.com> wrote:
I came across this because I was setting up a CI run against Python3.9. On Py3.9 there is a DeprecationWarning if `math.factorial` is supplied a float:
On Py3.8: math.factorial(2.0) --> 2
On Py3.9: math.factorial(2.0) --> 2 and emits a "DeprecationWarning: Using factorial() with floats is deprecated"
Presumably with Py >> 3.9: math.factorial(2.0) will raise an Exception
As you say, `math.factorial` is used by `special.factorial` for `exact=True`. When Python3.9 is released various tests will start to fail because of that DeprecationWarning. I know it's early days, I'm just trying to be proactive.
- how to modify tests to account for that DeprecationWarning when `special.factorial` is supplied a float with `exact=True` - how test code and special.factorial code has to be modified for a post DeprecationWarning period.
I'd probably just wrap `math.factorial()` with something that does the current `ValueError` check when a non-integral float is passed and just casts to `int` otherwise before passing it onto `math.factorial()`. If passing integral floats made it into our tests, it's surely made it into real code. -- Robert Kern
participants (2)
-
Andrew Nelson
-
Robert Kern