Re: A better math.factorial
On Sat, Sep 18, 2021 at 03:50:00PM -0700, Christopher Barker wrote:
Folks are not surprised by:
2 * 3 == [2] * 3
False
Because 2 is not only a different type than [2] but because they are different values as well.
What counts as a value? In some programming languages, 2.0 != 2 and I can't say that they are wrong to make that decision. Given: a, = [2] b, = (2,) then clearly a==b. In that sense, we can say that the two sequences have the same value. But: [2] != (2,) [2]*5 != (2,)*5 so in Python, the concept of "same value" does depend on type. Numeric types are an exception, because they are automatically coerced to a common type. And that's a mixed benefit. It means that we have to deal with surprises like this: >>> 1234567890123456789 == 1234567890123456789.0 False Even more surprising: >>> x = 1234567890123456789 >>> x == x + 0 True >>> x == x + 0.0 False I still think that there is little or no justification for having factorial automatically delegate to gamma *in Python*, but there are languages where it would work. In the right circumstances, it works fine. It's not a dumb idea. For instance, in Javascript, there is no int type, everything is a float. So in Javascript, there is no question that factorial(65) will unquestionably equal factorial(65.0), and that it would be perfectly safe to have factorial take fractional values and compute the gamma function. Similarly for the various calculator languages used in advanced programmable calculators, where it is the case that fractional arguments to factorial return the gamma function. (Possibly in symbolic form.) -- Steve
On Sun, Sep 19, 2021 at 1:44 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Sat, Sep 18, 2021 at 03:50:00PM -0700, Christopher Barker wrote:
Folks are not surprised by:
2 * 3 == [2] * 3
False
Because 2 is not only a different type than [2] but because they are different values as well.
What counts as a value? In some programming languages, 2.0 != 2 and I can't say that they are wrong to make that decision.
Given:
a, = [2] b, = (2,)
then clearly a==b. In that sense, we can say that the two sequences have the same value.
Hmm. While I agree with your point, I dispute that justification. Unpacking two different things can definitely yield the same results, even though the things themselves have very different values. a, = {2: "two"} a, = {2: "three?"} a, = (lambda: (yield 2))() Those are very different values, but when you unpack them, they happen to behave similarly (or rather, iterating over each one yields the same single value). It's hard to say in general what it truly means to "have the same value", but when we're talking about numeric types, the simplest definition is "they represent the same number within a family of compatible types". In Python, all numeric types are deemed to be compatible, so if the number represented is the same, Python treats them as equal (2 == 2.0 == Fraction(2, 1) == 2+0j), but other languages may choose to deem some or all types to be incompatible (thus 2==2.0 would be a TypeError). Either makes sense. Numbers, for once, are fairly easy to handle.
Numeric types are an exception, because they are automatically coerced to a common type. And that's a mixed benefit. It means that we have to deal with surprises like this:
>>> 1234567890123456789 == 1234567890123456789.0 False
Even more surprising:
>>> x = 1234567890123456789 >>> x == x + 0 True >>> x == x + 0.0 False
And that's why it does make perfectly good sense to decide that the domain of integers is entirely separate from the domain of floats (both are subsets of reals but they have only limited overlap). Neither choice is fundamentally wrong.
I still think that there is little or no justification for having factorial automatically delegate to gamma *in Python*, but there are languages where it would work. In the right circumstances, it works fine. It's not a dumb idea.
For instance, in Javascript, there is no int type, everything is a float. So in Javascript, there is no question that factorial(65) will unquestionably equal factorial(65.0), and that it would be perfectly safe to have factorial take fractional values and compute the gamma function.
Except for the fact that JavaScript doesn't really have much of a math library, yes :) I would actually be extremely surprised if JS had a built-in or standard library function for gamma. Though factorials, in my experience, are far more commonly a demonstration of recursion than any sort of actual utility. I honestly cannot think of a single time when I've wanted to reach for a standard library factorial function. ChrisA
Chris Angelico writes:
Though factorials, in my experience, are far more commonly a demonstration of recursion than any sort of actual utility. I honestly cannot think of a single time when I've wanted to reach for a standard library factorial function.
I gather you've never accumulated karma such that your sentence was teaching high school combinatorics (aka "finite math"). ;-)
participants (3)
-
Chris Angelico
-
Stephen J. Turnbull
-
Steven D'Aprano