Last Nonzero Digits of a Factorial in Base

22

2

You should write a program or function which given three positive integers n b k as input outputs or returns the last k digits before the trailing zeros in the base b representation of n!.

Example

n=7 b=5 k=4
factorial(n) is 5040
5040 is 130130 in base 5
the last 4 digits of 130130 before the trailing zeros are 3013
the output is 3013

Input

  • 3 positive integers n b k where 2 <= b <= 10.
  • The order of the input integers can be chosen arbitrarily.

Output

  • A list of digits returned or outputted as an integer or integer list.
  • Leading zeros are optional.
  • Your solution has to solve any example test case under a minute on my computer (I will only test close cases. I have a below-average PC.).

Examples

New tests added to check correctness of submissions. (They are not part of the under 1 minute runtime rule.)

Input => Output (with the choice of omitting leading zeros)

3 10 1  =>  6

7 5 4  =>  3013

3 2 3  =>  11

6 2 10  =>  101101

9 9 6  =>  6127

7 10 4  =>  504

758 9 19  =>  6645002302217537863

158596 8 20  =>  37212476700442254614

359221 2 40  =>  1101111111001100010101100000110001110001

New tests:
----------

9 6 3  =>  144

10 6 3  =>  544

This is code-golf, so the shortest entry wins.

randomra

Posted 2015-04-30T12:54:34.810

Reputation: 19 909

1under a minute on my computer is a little difficult to aim for if we don't know any specifics. – Dennis – 2015-04-30T17:04:18.137

1Would 7 5 3 output "013" or "13"? – Claudiu – 2015-04-30T17:06:43.090

1@Claudiu based on the 7 10 4 test case I would say 13 – Maltysen – 2015-04-30T17:07:33.070

2@Claudiu "Leading zeros are optional." so both version is correct. – randomra – 2015-04-30T17:12:45.177

I'm having a hard time understanding the algorithm necessary. Can someone help explain? I'm looking here, but it's a bit different since there's a change of base: http://mathforum.org/library/drmath/view/71768.html

– mbomb007 – 2015-04-30T17:13:23.007

If we choose integer list for output, does endianness matter? – Dennis – 2015-04-30T17:16:39.537

@Dennis Yes, endianness matters. I used the 1 min rule to clearly separate the simple O(n^2) algorithms from the rest but that might have been a failed attempt. – randomra – 2015-04-30T17:24:39.757

wont you settle a score-meter for this ? – Abr001am – 2015-04-30T22:41:49.150

Is a list of integers as output OK, or is a string required? – isaacg – 2015-05-01T02:09:18.147

@isaacg It is ok. "A list of digits returned or outputted as an integer or integer list." (just edited the , to or). – randomra – 2015-05-01T02:13:54.593

Do you have bounds for n? – Brian J – 2015-05-01T17:19:04.623

1Must we accept any positive integer for n or k? Or can we limit them to the range of the language's integer type? – Toby Speight – 2016-01-19T21:06:37.917

@TobySpeight Your integer type can limit the range where you can solve the problem but the given should cause no problem for your code. – randomra – 2016-01-19T22:12:02.763

Are you going to change the accepted answer with the renewed interest? – Adám – 2016-01-20T22:09:42.080

Answers

1

Dyalog APL, 23 bytes

⌽k↑⌽{⍵↓⍨-⊥⍨0=⍵}b⊥⍣¯1⊢!n

This program works as long as the factorial does not exceed internal representation limit. In Dyalog APL, the limit can be raised by ⎕FR←1287.

Assumes the variables n, b, and k have been set (e.g. n b k←7 5 4), but if you rather want prompting for n, b, and k (in that order) then replace the three characters with .

Adám

Posted 2015-04-30T12:54:34.810

Reputation: 37 779

Every test case I threw at it was computed in about 11 microseconds on my machine (M540). – Adám – 2016-01-20T15:20:55.607

7

Mathematica, 57 48 bytes

Saved 9 bytes thanks to @2012rcampion .

IntegerString[#!/#2^#!~IntegerExponent~#2,##2]&

alephalpha

Posted 2015-04-30T12:54:34.810

Reputation: 23 988

I've never really used mathematica, but couldn't you swap the order of the arguments to make b first to save 2 bytes? – FryAmTheEggman – 2015-04-30T18:06:56.400

@FryAmTheEggman I'm new to the golfing community, is swapping argument order "kosher"? – 2012rcampion – 2015-04-30T18:34:23.823

1You can actually get to 47: IntegerString[#!#2^-#!~IntegerExponent~#2,##2]& (both this and your original are quite fast) – 2012rcampion – 2015-04-30T18:44:31.960

The asker wrote: "The order of the input integers can be chosen arbitrarily." under input, so in this case it's definitely fine – FryAmTheEggman – 2015-04-30T18:46:52.897

@Fry Wow, looks like I didn't read closely enough. However, the SlotSequence trick I used in my comment only works with the current order, so you couldn't save any more. – 2012rcampion – 2015-04-30T23:50:30.653

7

Python, 198 192 181 chars

def F(n,b,k):
 p=5820556928/8**b%8;z=0;e=f=x=1
 while n/p**e:z+=n/p**e;e+=1
 z/=1791568/4**b%4;B=b**(z+k)
 while x<=n:f=f*x%B;x+=1
 s='';f/=b**z
 while f:s=str(f%b)+s;f/=b
 return s

It's fast enough, ~23 seconds on the biggest example. And no factorial builtin (I'm looking at you, Mathematica!).

Keith Randall

Posted 2015-04-30T12:54:34.810

Reputation: 19 865

[2,3,2,5,3,7,2,3,5][b-2] could be int('232537235'[b-2]) to save 3 bytes. [1,1,2,1,1,1,3,2,1][b-2] similarly. – randomra – 2015-05-01T01:10:19.877

For the latter, a lookup table 111973>>2*(b-2)&3 is even shorter. It's the same number of bytes for the former though (90946202>>3*(b-2)&7). – Sp3000 – 2015-05-01T02:51:19.567

nvm looks like you were right about the higher digits thing – Sp3000 – 2015-05-01T03:17:11.200

I believe you can save a few bytes by making this a program and not a function. – FryAmTheEggman – 2015-05-03T17:21:19.083

6

Pyth, 26 35 bytes

M?G%GHg/GHH.N>ju%g*GhHT^T+YslNN1T_Y

This is a function of 3 arguments, number, base, number of digits.

Demonstration.

The slowest test case, the final one, takes 15 seconds on my machine.

isaacg

Posted 2015-04-30T12:54:34.810

Reputation: 39 268

@Sp3000 I added a fix which I think should be sufficient. – isaacg – 2015-05-01T05:31:43.467

2

PARI/GP, 43 bytes

Trading speed for space yields this straightforward algorithm:

(n,b,k)->digits(n!/b^valuation(n!,b)%b^k,b)

Each of the test cases runs in less than a second on my machine.

Charles

Posted 2015-04-30T12:54:34.810

Reputation: 2 435

2

Mathematica - 48 bytes

#!~IntegerDigits~#2/.{l__,0...}:>{l}~PadLeft~#3&

Ungolfed:

Function[{n, b, k},
  IntegerDigits[n!, b] (* list of the base-b digits in n! *)
  /. {l__, 0...} (* match a sequence of elements l and some number of zeros*)
                 (* lucky for me, __ defaults to match the shortest number *)
     :> PadLeft[List[l], k] (* pad l to be k elements long with zeros on the left *)
                            (* this truncates the list if it is too long*)
]

Example:

#!~IntegerDigits~#2/.{l__,0...}:>{l}~PadLeft~#3 &
%[758, 9, 19] // Timing

(* {0.031250, {6, 6, 4, 5, 0, 0, 2, 3, 0, 2, 2, 1, 7, 5, 3, 7, 8, 6, 3}} *)

For the largest cases, the limiting factor is not generating the digits:

Length@IntegerDigits[359221!, 2] // Timing
(* {0.109375, 6111013} 6.1M digits in 100 ms *)

The pattern matching seems to be O(n^2), causing the last two test cases to go far over the one-minute mark.

2012rcampion

Posted 2015-04-30T12:54:34.810

Reputation: 1 319

2

Haskell, 111 109 bytes

import Data.Digits
f n b k=digits b$foldl(((unDigits b.reverse.take k.snd.span(<1).digitsRev b).).(*))1[1..n]

Usage: f 158596 8 20 -> [3,7,2,1,2,4,7,6,7,0,0,4,4,2,2,5,4,6,1,4]

Takes about 8 seconds for f 359221 2 40 on my 4 year old laptop.

How it works: fold the multiplication (*) into the list [1..n]. Convert every intermediate result to base b as a list of digits (least significant first), strip leading zeros, then take the first k digits and convert to base 10 again. Finally convert to base b again, but with most significant digit first.

nimi

Posted 2015-04-30T12:54:34.810

Reputation: 34 639

you had the idea in my mind , that i was interpreting it using matlab , what a coincidende :D – Abr001am – 2015-05-01T16:52:55.190

2

Bash/coreutils/dc, 60 bytes

dc<<<"1 `seq -f%g* $1`$2op"|sed -r s/0+$//|tail -c$(($3+1))

Uses the dc script from my answer to Find the Factorial, outputting in base $2, with sed to trim trailing zeros and tail to select the last $3 digits.

Toby Speight

Posted 2015-04-30T12:54:34.810

Reputation: 5 058

I have to admit that it's extremely slow with the 40-bit base-2 testcase. I tried easing sed's work using rev to reduce backtracking, but it's dc that's eating the CPU... – Toby Speight – 2016-01-20T22:44:29.920

1

Python 3, 146 bytes

import math
i,f=input(),int
n=i.split()
e=math.factorial(f(n[0]))
d=''
while e>0:
 d=str((e%f(n[1])))+d;e=e//f(n[1])
print(d.strip('0')[-f(n[2]):])

I'm not sure the test cases will all run fast enough - the larger ones are very slow (as it is looping through the number).

Try it online here (but be careful).

Tim

Posted 2015-04-30T12:54:34.810

Reputation: 2 789

1

Java, 303 299 296 bytes

import java.math.*;interface R{static void main(String[]a){BigInteger c=new BigInteger(a[1]),b=c.valueOf(1);for(int i=new Integer(a[0]);i>0;i--){b=b.multiply(b.valueOf(i));while(b.mod(c).equals(b.ZERO))b=b.divide(c);b=b.mod(c.pow(new Integer(a[2])));}System.out.print(b.toString(c.intValue()));}}

On my computer, this averages a little under a third of a second on the 359221 2 40 testcase. Takes input via command line arguments.

SuperJedi224

Posted 2015-04-30T12:54:34.810

Reputation: 11 342

1

bc, 75 bytes

define void f(n,b,k){
obase=b
for(x=1;n;x%=b^k){
x*=n--
while(!x%b)x/=b}
x}

This uses some GNU extensions to reduce code size; a POSIX-conforming equivalent weighs in at 80 bytes:

define f(n,b,k){
obase=b
for(x=1;n;x%=b^k){
x*=n--
while(x%b==0)x/=b}
return(x)}

To keep run times reasonable, we trim the trailing zeros (while(!x%b)x/=b) and truncate to the final k digits (x%=b^k) as we compute the factorial (for(x=1;n;)x*=n--).

Test program:

f(3, 10, 1)
f(7, 5, 4)
f(3, 2, 3)
f(6, 2, 10)
f(9, 9, 6)
f(7, 10, 4)
f(758, 9, 19)
f(158596, 8, 20)
f(359221, 2, 40)
f(9, 6, 3)
f(10, 6, 3)
quit

Runtime of the full test suite is approx 4¼ seconds on my 2006-vintage workstation.

Toby Speight

Posted 2015-04-30T12:54:34.810

Reputation: 5 058

This is my first ever bc program (golf or not), so any tips are especially welcome... – Toby Speight – 2016-01-20T11:17:11.087

0

PHP, 80 bytes

function f($a,$b,$c){echo substr(rtrim(gmp_strval(gmp_fact($a),$b),"0"),-1*$c);}

Used as f(359221,2,40) for the last test case. Runs pretty smoothly for all test cases.

Try here !

Paul Picard

Posted 2015-04-30T12:54:34.810

Reputation: 863