[Jprogramming] Trying to handle large factorials -- odd error
Geoff Canyon
geoffc at inspiredlogic.com
Thu Mar 27 23:18:22 HKT 2008
Thanks for the tip! I solved my problem by switching to
f =: (((|.&.":)@(5{.":&(".@(,&'x')@|.&":)))@*)/
I should have been more clear. I'm talking _very_ large factorials:
100,000 up to perhaps a million. For numbers like those, simply doing !
100000x and then extracting the last five non-zero digits is at best
inefficient and likely a go-make-a-cup-of-coffee proposition.
At each step, only the last five non-zero digits need to be kept, so
for example, rather than multiplying 10001 by !10000x (a 35660-digit
number) and then getting the digits I want, I just multiply 10001 by
79008 (the last five non-zero digits of !10000x) to get the last five
non-zero digits of !10001. At least, that's the plan.
And it seems to work:
f =: (((|.&.":)@(5{.":&(|.&.":)))@*)/
Ts 'f >:i.5000x'
0.0493279 782208
Ts 'f >:i.6000x'
0.059438 918400
Ts 'f >:i.7000x'
0.0696259 1.05459e6
So I don't like the storage requirements, but the time taken appears
to be scaling roughly linearly, which it doesn't come near to doing
with actual factorials. Looking at it more concretely, consider my
code vs. ! for 10000x:
Ts 'f >:i.10000x'
0.0983548 1.56147e6
Ts '!10000x'
1.08737 1.01062e6
My code is 100 times faster, although it takes more space. I figure
that the way to solve both the space issue might be to switch to a
recursive function.
regards,
Geoff
On Mar 26, 2008, at 10:40 PM, bill lam wrote:
> You need to add the trailing 'x' to the formatted number.
> I'm unskillful in writing tacit form but the following seems
> implementing your logic.
> _5{. |. ": ". ,&'x' |. ": */ 1+i.10x
> 36288
> _5{. |. ": ". ,&'x' |. ": */ 1+i.20x
> 17664
> _5{. |. ": ". ,&'x' |. ": */ 1+i.10050x
> 69696
>
> btw I think that ! should be more efficient than */@:>:@:i.
>
> Geoff Canyon wrote:
>> I'm trying to find the last five non-zero digits of a large
>> factorial. So for:
>> !10x = 3628800
>> the answer would be 36288 while for:
>> !20x = 2432902008176640000
>> the answer would be 17664.
>> I'm trying to do this by calculating /* 1+i.1000 without
>> calculating large numbers by losing the trailing zeroes at each
>> step and the leading digits more than five. Here's what I have so
>> far:
>> (((|.&.":)@(5{.":&(|.&.":)))@*)/ 1+i.20x
>> The truncating code:
>> -- Converts to string, transposes, and converts back to a number.
>> That loses trailing zeroes (because they're now leading zeroes).
>> -- Converts to string and grabs the first five characters (which
>> were the last five non-zero digits).
>> -- Converts to string again -- not sure why this is necessary, but
>> it doesn't work otherwise -- transposes, and converts back to a
>> number.
>> This whole thing is performed atop *, and the resulting verb is
>> inserted into the list from 1 to a large number.
>> This seems to work for large numbers up to 10049x. At 10050x I get
>> an ill-formed number error.
>> Where did I go wrong?
>> regards,
>> Geoff
>> ----------------------------------------------------------------------
>> For information about J forums see http://www.jsoftware.com/
>> forums.htm
>
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
>
More information about the Programming
mailing list