Your test with all.equal
does not produce what you expect. all.equal
can only compare two values. The third argument is positionally matched to tolerance
, which gives the tolerance of the comparison operation. In your invocation to all.equal
you give it a tolerance of 100!
which definitely leads to the comparison being true for absurdly differing values:
> all.equal( 0, 1000000000, prod(as.double(1:100)) )
[1] TRUE
But even if you give it two arguments only, e.g.
all.equal( prod(1:100), factorial(100) )
it would still produce TRUE
because the default tolerance is .Machine$double.eps ^ 0.5
, e.g. the two operands have to match to about 8 digits which is definitely the case. On the other hand, if you set the tolerance to 0
, then neither three possible combinations emerge equal from the comparison:
> all.equal( prod(1:100), factorial(100), tolerance=0.0 )
[1] "Mean relative difference: 1.986085e-14"
> all.equal( prod(1:100), prod( as.double(1:100) ), tolerance=0.0 )
[1] "Mean relative difference: 5.22654e-16"
> all.equal( prod(as.double(1:100)), factorial(100), tolerance=0.0 )
[1] "Mean relative difference: 2.038351e-14"
Also note that just because you've told R to print 200 significant numbers doesn't mean that they are all correct. Indeed, 1/2^53 has about 53 decimal digits but only the first 16 are considered meaningful.
This also makes your comparison to the "true" value flawed. Observe this. The ending digits in what R gives you for factorial(100)
are:
...01203456
You subtract n
from it, where n
is the "true" value of 100! so it should have 24 zeroes at the end and hence the difference should also end with the same digits that factorial(100)
does. But rather it ends with:
...58520576
This only shows that all those digits are non-significant and one should not really look into their value.
It takes 525 bits of binary precision in order to exactly represent 100! - that's 10x the precision of double
.