[S] Follow up to "Don't assume factorial() gives you integer values"

Steven P. Millard (steven.p.millard@mci2000.com)
Mon, 30 Nov 1998 10:32:43 -0800


Thanks for the quick replies from Brian Ripley, Paul Tukey, and Scott
Chaslow regarding the behavior of factorial().

I apologize that I forgot to mention what version of S-PLUS I am using:
S-PLUS 4.5 for Windows, Release 2.


Brian Ripley points out that this problem is fixed in S-PLUS 5.0:

> length(numeric(factorial(8)))
[1] 40320
> class(factorial(8))
[1] "numeric"

As a Windows User, however, I think I'll be waiting quite a few months
for S-PLUS 5.0.


Paul Tukey points out I could use a custom function that works just for

bang <- function(n) prod(n:1)


Scott Chaslow notes:

"I don't know if I would call this a bug, but this type of thing does
seem to bite people often. My advice is to never ever assume a number
is an integer unless you type it in explicitly that way:
length(numeric(40320)) had better work as advertised;
length(numeric(factorial(8))) need not, because I know not to assume
that factorial(8) returns an integer. Better coding practice might be
something like: numeric(round(factorial(8)))."


As for my proposed solution of requiring factorial() to return an
integer if you give it an argument of mode integer, Scott Chaslow
writes (and I agree with him):

" At first glance, this might seem a reasonable solution. But I
personally would not be comfortable relying on such behaviour. I still
would use numeric(round(factorial(8))). Why? Because factorial() is
not the only function around that might be expected to return integers
sometimes, I think it would be hard to make sure all such functions
conformed to your suggested fix, and I would never remember which ones
I have dealt with a similar issue before for my function nCm (included
below) from my combinat library. There I added an argument which
allows the user to choose whether or not she wishes the answer rounded
to an integer. I did this because although I know perfectly well that
a binomial coefficient need not be an integer, most users probably
expect it to be so. I like this solution because it is pretty
transparent, at least if you look at the documentation or the argument
list. Having the return value silently differ depending on whether you
pass 8 or as.integer(8) strikes me as dangerous and sneaky."


Original Post:

Hello Everyone,

Here is one that bit me recently. The factorial() function calls the
gamma() function, so for example you can compute factorial(2.7). Now

> factorial(8)
[1] 40320

> length(numeric(factorial(8)))
[1] 40319

I consider this a bug. I assume this has to do with machine
representation, but it would be nice if the factorial function gave you
a result in integer mode if you supply it with an argument that is an

When I say "an argument that is an integer", however, I have to be
careful since you get the following:

> is.integer(8)
[1] F

so I guess I'm proposing that if the argument to factorial() is
explicitly set to integer mode, then the result should be an integer.
That is, I'd like to see the following behavior:

> length(numeric(factorial(as.integer(8))))
[1] 40320



--Steve M.

| *** | Steven P. Millard, Ph.D.
| * |
| * * * | P robability, TEL: 206-528-4877
| * * * | S tatistics & FAX: 206-528-4802
| * | I nformation E-mail: SMillard@ProbStatInfo.com
| * | Web: www.ProbStatInfo.com
| *** | 7723 44th Avenue NE
|___________| Seattle, WA 98115-5117 USA

This message was distributed by s-news@wubios.wustl.edu. To unsubscribe
send e-mail to s-news-request@wubios.wustl.edu with the BODY of the
message: unsubscribe s-news