Well, I wouldn't have used such colorful language, but I share
Prof. Fateman's skepticism on the utility of lgamma for computing
factorials.

I tried the expression as given, (see attachment, if you want to try
yourself or point out errors) and it begins to diverge from the correct
value at n=17 (which is a bit more than 48 bits for the integer).
Interestingly, if I switch to gamma(), instead of exp(lgamma()), it
doesn't diverge until n=23, which corresponds to a 75 bit number.
(Presumably there are a lot of zeros at the bottom of a factorial.)
So, that *would* work if you were in C and restricted to 64 bit long
longs.  But, as Fateman points out, with that restriction you might as
well keep a short table.

Of course, in Python we expect thousands of bits to work
transparently, so I would definitely avoid converting from lgamma to
an int.

BTW, I don't understand the "far superior" implementation of fact
later in the posting.  When I try it, I just get regular linear
recursion.  Presumably there is a typo in my translation or in the
original posting.

On Saturday, May 3, 2014 4:35:41 PM UTC-7, Richard Fateman wrote:
>
>
>
> On Tuesday, April 1, 2014 2:58:34 PM UTC-7, Ondřej Čertík wrote:
>>
>> On Mon, Mar 31, 2014 at 9:14 PM, Matthew Rocklin <mroc...@gmail.com> 
>> wrote: 
>> > http://www.evanmiller.org/mathematical-hacker.html 
>> > 
>> > I reference that blog post pretty often.  I fully intend to reference 
>> it 
>> > again in my talk (if it is accepted). 
>>
>
> That's unfortunate.  I was totally unacquainted with Evan Miller.  I read 
> this particular
> blog entry.  I did not follow any of the links, but I think that the essay 
> is a piece of crap.
> It is uninformed, shallow, and, I daresay, just wrong.  I hope you 
> re-think referring to it.
>
>  
>
>> > 
>> > The interesting thing about the Factorial / Gamma / loggamma example is 
>> that 
>> > to find the solution you need to find someone who knows both that n! = 
>> > Gamma(n+ 1) and who knows that a loggamma routine is commonly found in 
>> lower 
>> > level languages.  Those bits of information are usually held by 
>> different 
>> > experts.  Ondrej said "Of course, that's obvious" when I first reposted 
>> the 
>> > article on G+. 
>>
>
> Well, let me quote from the article..
> "
> *if it is ever necessary to compute a factorial, a programmer should be 
> taught to take advantage of the system's log-gamma function, as the 
> following C code does: *
>
> *
> long int fac(unsigned long int n) {
>     return lround(exp(lgamma(n+1)));
> }
> *
>
> * Again, no recursion is required as long as one...*
>
> Here are a few things that are wrong. Rounding an approximate floating 
> point
> number to a integer may not get you the exact integer factorial you want.
> The program will certainly not work for arbitrary unsigned long int n 
> because
> the exp() will overflow. Say certainly by n=175.
> If you want a floating-point approximation to any factorial that can be
> represented as an IEEE double, you could do it by checking if N<175 and
> then index into an array of length 175.  [I'd check that 175 more carefully
> if I were really doing this.  And the number would change a little for 
> 64-bit ints.
>
> If you want exact integer factorials on a 32 bit computer, you only need 
> an array of 12, since
> 13! > 2^32.
>
> So the program is stupid.  Why?  Because the author is mathematically
> and computationally ignorant.  (And seemingly quite full of himself.)
>
> Say you want to solve the much more interesting problem of computing 
> factorials
> of any size integer.  Then you might see
> http://www.luschny.de/math/factorial/FastFactorialFunctions.htm
> which tells how it might be done better.
>
> Here's a far superior factorial, in lisp, and yes it is recursive.  I 
> suppose you
> could write it iteratively, but why bother. A Lisp compiler will do that 
> for you.
>
> (defun fact(n)(f n 1))
>
>  (defun f (n m) (if (<= n 1) 1 (* n (f (- n m) m))))
>
> It is used in some computer algebra systems.
>
>
> The snide characterizations that lisp programmers know more or less 
> mathematics
> or that what they know is more or less relevant is just junk.
>
> Of the 3 people quoted -- Raymond, Graham, Yegge...
> I've never heard of Yegge; I think that Graham is smart, and Raymond just 
> says things
> to be, uh, smart-ass.  
>
>
>
>
>  
>
>>
>> That's funny, I forgot that I said that and just had the same reaction. 
>>
>> However, we are still missing rational function approximation in SymPy 
>> or mpmath. 
>> That's what is used to implement things like log_gamma or erf (error 
>> function) in 
>> Fortran or C. So I have just created an issue for it: 
>>
>> https://github.com/sympy/sympy/issues/7359 
>>
>> and I spent time explaining exactly how it works in it and giving 
>> examples, 
>> including for example the implementation of erf() in gfortran. 
>>
>> Aaron, you were asking about examples of numerical cancellation. I 
>> worked out one in the 
>> issue as well. 
>>
>> Ondrej 
>>
>> > 
>> > You're right that this is similar to my last talk.  The last one though 
>> was 
>> > mostly about an application (numerical linear algebra).  I actually 
>> want to 
>> > talk a bit more about the philosophy and some of the more abstract 
>> tools 
>> > that people might actually use.  Your first impression is a valuable 
>> one 
>> > though, I should go through my last talk and make sure that I'm not 
>> > repeating too much that shouldn't be repeated. 
>> > 
>> > 
>> > On Mon, Mar 31, 2014 at 6:03 PM, Aaron Meurer <asme...@gmail.com> 
>> wrote: 
>> >> 
>> >> That's a good point. One of the nicest things about symbolics, when 
>> you 
>> >> can get it, is that it can make things drastically more efficient by 
>> doing 
>> >> mathematical simplifications. Evaluating integrals symbolically is a 
>> nice 
>> >> example of this (especially for SymPy, which has some pretty nice 
>> algorithms 
>> >> to compute definite integrals). 
>> >> 
>> >> I'm reminded of a popular blog post (I can't find a link right now) 
>> about 
>> >> how know math is important for programmers. It has the example of how 
>> all 
>> >> these programming languages show how they they compute factorial, and 
>> how 
>> >> tail recursion can make it linear or whatever, but the actual best way 
>> to 
>> >> compute it is to use loggamma, which gives the answer in constant 
>> time. 
>> >> 
>> >> Aaron Meurer 
>> >> 
>> >> 
>> >> On Mon, Mar 31, 2014 at 7:51 PM, Tim Lahey <tim....@gmail.com> wrote: 
>> >>> 
>> >>> 
>> >>> 
>> >>> On 31 Mar 2014, at 20:29, Aaron Meurer wrote: 
>> >>> 
>> >>>> On Mon, Mar 31, 2014 at 11:32 AM, Matthew Rocklin 
>> >>>> <mroc...@gmail.com>wrote: 
>> >>>> 
>> >>>>> I like that you emphasized the utility for numerics, I think that 
>> this 
>> >>>>> is 
>> >>>>> likely to be a selling point for the SciPy crowd. 
>> >>>>> 
>> >>>> 
>> >>>> Yes, this was very intentional. I may need some help gathering up 
>> some 
>> >>>> nice 
>> >>>> motivating examples if this is accepted. 
>> >>> 
>> >>> 
>> >>> One motivating example for me is the integration of products of 
>> functions 
>> >>> over areas and volumes. For finite elements, you'll get products of 
>> pairs of 
>> >>> trial functions (usually polynomials). It's even more useful for 
>> products of 
>> >>> trig functions. Performing the integration of any of theses is easy 
>> enough 
>> >>> with numerical integration, but it's much more efficient to calculate 
>> the 
>> >>> integrals symbolically and then perform the evaluation for each 
>> element. 
>> >>> 
>> >>> Cheers, 
>> >>> 
>> >>> Tim. 
>> >>> 
>> >>> 
>> >>> -- 
>> >>> You received this message because you are subscribed to the Google 
>> Groups 
>> >>> "sympy" group. 
>> >>> To unsubscribe from this group and stop receiving emails from it, 
>> send an 
>> >>> email to sympy+un...@googlegroups.com. 
>> >>> To post to this group, send email to sy...@googlegroups.com. 
>> >>> Visit this group at http://groups.google.com/group/sympy. 
>> >>> To view this discussion on the web visit 
>> >>> 
>> https://groups.google.com/d/msgid/sympy/AE5C61B5-8C69-49AE-BAFF-85E5AC924F8F%40gmail.com.
>>  
>>
>> >>> 
>> >>> For more options, visit https://groups.google.com/d/optout. 
>> >> 
>> >> 
>> >> -- 
>> >> You received this message because you are subscribed to the Google 
>> Groups 
>> >> "sympy" group. 
>> >> To unsubscribe from this group and stop receiving emails from it, send 
>> an 
>> >> email to sympy+un...@googlegroups.com. 
>> >> To post to this group, send email to sy...@googlegroups.com. 
>> >> Visit this group at http://groups.google.com/group/sympy. 
>> >> To view this discussion on the web visit 
>> >> 
>> https://groups.google.com/d/msgid/sympy/CAKgW%3D6K8F9weBP-7yjpzrN9hQ5FR54TK_QdCPqbzBdwo20zKdg%40mail.gmail.com.
>>  
>>
>> >> 
>> >> For more options, visit https://groups.google.com/d/optout. 
>> > 
>> > 
>> > -- 
>> > You received this message because you are subscribed to the Google 
>> Groups 
>> > "sympy" group. 
>> > To unsubscribe from this group and stop receiving emails from it, send 
>> an 
>> > email to sympy+un...@googlegroups.com. 
>> > To post to this group, send email to sy...@googlegroups.com. 
>> > Visit this group at http://groups.google.com/group/sympy. 
>> > To view this discussion on the web visit 
>> > 
>> https://groups.google.com/d/msgid/sympy/CAJ8oX-HZABscP43PDuoAeWhcpBYW2w39G8qPx0%2BZCbKcYbJdJg%40mail.gmail.com.
>>  
>>
>> > 
>> > For more options, visit https://groups.google.com/d/optout. 
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sympy+unsubscr...@googlegroups.com.
To post to this group, send email to sympy@googlegroups.com.
Visit this group at http://groups.google.com/group/sympy.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sympy/f999c5c5-b99b-46bf-a40b-5d1eb5ff11e6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
import math

def fact(n):
    """Factorial algorithm from R. Fateman sympy group post.  Gives
    correct values, but seems to result in ordinary linear
    behavior."""
    return f(n, 1)

def f(n, m):
    """Semantics?"""
    if n<=1:
        return 1
    return n*f(n-m, m)

def miller_fac(n):
    """Factorial approximation, based on Evan Miller blog post."""
    return int(math.exp(math.lgamma(n+1)) + 0.5)

def miller2_fac(n):
    """Slight modification - use gamma instead of lgamma."""
    return int(math.gamma(n+1) + 0.5)

def test_factorial_implementations(fimpl, f_max):
    for n in xrange(f_max+1):
        base = math.factorial(n) # this should be exact
        f2 = fimpl(n)
        if base != f2:
            print "Discrepancy found for", n, base, f2
            print "lg of factorial", math.log(base, 2)
            
if __name__ == "__main__":
    print "Original expression, using exp(lgamma)"
    test_factorial_implementations(miller_fac, 20)
    print "Using Gamma"
    test_factorial_implementations(miller2_fac, 25)

Reply via email to