Dernier chiffre non nul de n!


22

Étant donné un entier 1 ≤ N ≤ 1 000 000 en entrée, sortez le dernier chiffre non nul de N! , où ! est le factoriel (le produit de tous les nombres de 1 à N , inclus). Il s'agit de la séquence OEIS A008904 .

Votre programme doit se terminer dans les 10 secondes sur une machine raisonnable pour toute entrée valide.

Cas de test

1 => 1
2 => 2
3 => 6
4 => 4
5 => 2
6 => 2
7 => 4
8 => 2
9 => 8
10 => 8
100 => 4
1000 => 2
10000 => 8
100000 => 6
1000000 => 4

C'est un donc le code le plus court en octets gagne!


Fonction unique ou programme complet?
Joey

@joey Non, ce ne sont que des cas de test. Entrée unique, sortie unique.
fR0DDY

@joey Programme complet.
fR0DDY

1
L'exigence d'un programme complet est déconseillée ...
Erik the Outgolfer

2
@EriktheOutgolfer il y a environ 7 ans, donc je ne pense pas que cela ait été déterminé à l'époque
NoOneIsHere

Réponses:


8

Rubis - 63 caractères

f=->n{n<2?1:6*[1,1,2,6,4,4,4,8,4,6][n%10]*3**(n/5%4)*f[n/5]%10}

Source - http://oeis.org/A008904

Gère jusqu'à un millier de chiffres en moins d'une seconde.

Tester

irb(main):014:0> for n in 2..6
irb(main):015:1> puts f[10**n]
irb(main):016:1> end
4
2
8
6
4

11

Mathematica, 45 36 octets

Last@Select[IntegerDigits[#!],#>0&]&

Très lisible pour une réponse gagnante. :) (Là encore, il n'y a pas encore de soumission GolfScript & Co.)

Cela gère 1 000 000 d'entrées en 5 secondes environ sur ma machine.


1
Mathematica est à peu près le langage parfait pour cette question.
Michael Stern

4

Python - 75

n=input()
g=1
while n:
 g*=n
 while g%10<1:g/=10
 g%=10**9
 n-=1
print g%10

3

PARI / GP - 27 octets

Cela échange la vitesse contre la taille - le boîtier de test prend beaucoup de temps (~ 6 secondes).

n->n!/10^valuation(n!,5)%10

Cette version est beaucoup plus rapide (~ 15 microsecondes) mais prend 81 octets:

n->r=1;while(n,r*=Mod(4,10)^(n\10%2)*[1,2,6,4,2,2,4,2,8][max(n%10,1)];n\=5);lift(r)

Vous pouvez utiliser ce code (non golfé) pour tester soit:

[%(10^n) | n <- [1..6]]

2

Windows PowerShell, 53 56 59 60 63 73 90

($a=1).."$input"|%{$a="$($a*$_)".trim('0')%1e7}
$a%10

Remarques:

  • Prend plus d'une minute pour un nombre proche de 100 000. Cependant, la suppression des zéros à la fin nécessite une conversion en chaîne, les calculs nécessitent un nombre, donc les conversions sont inévitables dans tous les cas.

Histoire:

  • 2011-02-08 10:31 (90) - Première tentative.
  • 2011-02-08 10:33 (73) - Le module est plus court que le découpage et l'assemblage.
  • 2011-02-08 10:34 (63) - Trim inutile.
  • 2011-02-08 10:37 (60) - Distribution inutile d'un nombre. Modulus le fait déjà très bien.
  • 2011-02-08 10:40 (59) - Certains en ligne.
  • 2011-02-08 11:00 (56) - Qu'est-ce que j'ai dit avant sur le module plus court? S'applique également à la sortie.
  • 2011-02-08 11:01 (53) - La conversion $inputen chaîne suffit; la conversion en intest appliquée implicitement.

2

Perl, 53 58 61 personnages

Tous les espaces peuvent être supprimés, mais je l'ai laissé pour "lisibilité". Remarque: n'utilisez pas de formule explicite idiote de Sloane.

sub f {
    $_ = $1 * ++$n || 1, /(.{1,7}?)0*$/ while $n < $_[0];
    $1 % 10
}

Calcule f (10 ^ 6) en 8,7 secondes sur ma machine.

Mise à jour : OP voulait que ce soit un programme complet:

$_ = $1 * ++$n || 1, /(.{1,7}?)0*$/ while $n < $ARGV[0];
print $1 % 10

Cela fait 55 caractères.


2

CJam - 28

1ri{I)*_AbW%{}#A\#/1e7%}fIA%

Vous pouvez l'essayer sur http://cjam.aditsu.net/ pour des valeurs jusqu'à 10000 environ; pour de plus grands nombres, vous devez utiliser l' interpréteur java . 1000000 s'exécute en environ 3 secondes sur mon ordinateur portable.

Explication:

Malheureusement, la solution simple est trop lente, donc je ne garde que les 7 derniers chiffres (avant les zéros de fin) après chaque multiplication.

1           push 1 on the stack
ri          read a token and convert to integer
{           loop (for I from 0 to N - 1)
    I)      push I and increment
    *       multiply with the previous value (initially 1)
    _Ab     duplicate and convert to array of digits
    W%      reverse array
    {}#     find the position of the first non-zero digit
    A\#     raise 10 to that power
    /       divide, thus removing all trailing zeros
    1e7%    keep the remainder modulo 10000000
}fI         end for loop
A%          get the last digit

Remarque: cette langue est beaucoup plus récente que la question.



2

05AB1E , 4 octets

!0м¤

Essayez-le en ligne!

Explication

!0    # Push the factorial of the input and 0
  м   # Remove the occurences of 0 in the factorial
   ¤  # Push the last element, implicit display

1
La version TIO a expiré (60s) sur le dernier cas de test - comment l'avez-vous obtenue dans les 10s sur une "machine raisonnable"?
Toby Speight

2

Gelée , 4 octets

!Ṛȯ/

Essayez-le en ligne!

Explication

Utilise le fait que lorsque (inverser une liste; ne vectorise pas) est appliqué à un entier, il prend automatiquementD (chiffres) en premier.

Avec l'entrée 8:

!Ṛȯ/
!     Factorial: 8! = 40320
 Ṛ    Reverse: [0,2,3,0,4]
   /  Reduce by...
  ȯ   ...logical OR: ((((0ȯ2)ȯ3)ȯ0)ȯ4) = first truthy element = 2

Je ne pense pas qu'il y ait un "premier élément véridique" d'un octet (qui ȯ/agit comme) mais s'il y en a un, cela peut être raccourci à trois octets au total.


2

Java (OpenJDK 8) , 62 octets

n->{long f=n;for(;n>1||f%10==0;)f=n>1?f*--n:f/10;return f%10;}

Essayez-le en ligne!

Similaire à @Kevin Cruijssen mais enregistre 5 octets en combinant les boucles.


Bienvenue chez PPCG! Bon premier post! J'espère que vous resterez!
Rɪᴋᴇʀ

Bienvenue chez PPCG! Je suis d'accord avec @Riker, excellent premier message. Bravo pour jouer mon code en combinant les boucles. Vous pouvez jouer au golf 1 octet de plus dans votre réponse actuelle en remplaçant ||par |, et un octet supplémentaire en remplaçant ==0par <1. Profitez de votre séjour!
Kevin Cruijssen

2

C, 150 140 135 octets

r,d;f(k,x){r=x<5?3:f(k+1,x/5);return(d=x%5)?r*"33436"[d]*(1<<d*k%4)%5:r;}main(int c,char**v){c=atoi(*++v);printf("%d",c<2?1:2*f(0,c));}

Il s'agit de la version pour les systèmes ASCII; remplacer la chaîne 33436par 11214pour un système EBCDIC, ou par\1\1\2\1\4 pour un programme portable.

Les solutions C sont un peu gênées par l'exigence de fournir un programme complet; cependant, cela répond pleinement à la question.

Essayez-le en ligne (nécessite Javascript):

Explication

Il est basé sur l'algorithme décrit dans le chiffre non nul le moins significatif de n! , se retourna pour que nous rentrions rapidement pour trouver la puissance la plus élevée de cinq, et fassions le calcul à la sortie. Les tables de constantes étaient trop grandes, je les ai donc réduites en trouvant une relation entre le résidu précédent r, le chiffre courant det la profondeur de récursivité k:

     0    1       2       3    4  =d
  0  0  3×2^k  1×2^2k  3×2^3k  2
  1  1  1×2^k  2×2^2k  1×2^3k  4
r 2  2  2×2^k  4×2^2k  2×2^3k  3
  3  3  3×2^k  3×2^2k  3×2^3k  2
  4  4  4×2^k  4×2^2k  4×2^3k  1

Pour r>0, ce à une fois décide Constante rfois 2^dk(mod 5); les constantes sont en a[]dessous (en ligne dans le code golfé). Nous observons également que (2^4)%5c'est 1, donc nous pouvons réduire l'exposant pour éviter de déborder la plage de int.

const int a[] = { 1, 1, 2, 1, 4 };
int f(int k, int x){
    int r = x<5 ? 3 : f(k+1,x/5); /* residue - from recursing to higher-order quinary digits */
    int d = x%5;
    if (!d)
        return r;
    return r * a[d] * (1<<d*k%4) % 5;
}

int main(int c, char **v)
{
    c = atoi(*++v);
    printf("%d",
           c<2
           ? 1                  /* special-case 0 & 1 */
           : 2*f(0,c));         /* otherwise, it's 2 times r */
}

Tests:

$ for i in 100 1000 10000 100000; do echo $i: `./694 $i`; done
100: 4
1000: 2
10000: 8
100000: 6
1000000: 4

La performance est également respectable. Voici une entrée maximale pour un système avec 32 bits int:

$ time ./694 2147483647
8
real    0m0.001s
user    0m0.000s
sys     0m0.000s

J'ai aussi les mêmes timings avec un maximum de 64 bits int.


1
Il peut être intéressant de noter qu'il 2147483647!compte plus de 19 milliards de chiffres et (2^63-1)!plus de 170 000 000 000 000 000 000 000 de chiffres, c'est donc une grande victoire sur le calcul des factorielles. 1000000!comme spécifié dans la question est possible de calculer sur le matériel actuel; c'est seulement 5½ millions de chiffres. :-)
Toby Speight

1

PHP - 105

 <?foreach(explode("\n",`cat`)as$n)if($n){$f=rtrim(gmp_strval(gmp_fact($n)),'0');echo substr($f,-1)."\n";}

Fonctionne en moins de 10 secondes avec le boîtier de test donné.


1

Python3

239 caractères

Peut faire 10000 en ~ 3,2 secondes (Ideone me coupe à 8 secondes, je suis sûr que cela prendra plus de 10 secondes :()

from functools import *
N=100
r=range
s=(p for p in r(2,N)if all(p%n>0for n in r(2,p)))
f=lambda n,x:n//x+(n//x>0and f(n//x,x)or 0)
e=list([p,f(N,p)]for p in s)
e[0][1]-=e[2][1]
e[2][1]=0
print(reduce(lambda x,y:x*y,map(lambda x:x[0]**x[1],e))%10)

Python2.6

299 caractères (un peu plus rapide)

from itertools import *
N=100000
r=xrange
def s(c=count(2)):
        while 1:p=c.next();c=ifilter(p.__rmod__,c);yield p
f=lambda n,x:n//x+(n//x>0and f(n//x,x)or 0)
e=[[p,f(N,p)]for p in takewhile(lambda x:x<N,s())]
e[0][1]-=e[2][1]
e[2][1]=0
print(reduce(lambda x,y:x*y,map(lambda x:pow(x[0],x[1],10),e))%10)

1

Haskell, 78 caractères

f n=head$dropWhile(=='0')$reverse$show$product[1..n]
main=interact(show.f.read)

(Aurait probablement besoin d'être compilé pour calculer 1 000 000! En 10 secondes).


Enregistrez deux caractères, remplacez-les foldl1par product(cf codegolf.stackexchange.com/questions/607/find-the-factorial/… ). Mais avez-vous réellement essayé avec 1000000! ?
JB

PS: pas un programme complet.
JB

Désolé, je l'ai fait avant que cela ne soit précisé dans les commentaires. Je vais le mettre à jour.
stusmith

1

J - 42 40 caractères

Tout un programme. Enregistrez ce programme dans un fichier et exécutez avec jconsole script.ijs 1234. Notez que ce programme ne quitte pas l'interpréteur après avoir imprimé un résultat. Tapez ^Dou exit]0pour quitter l'interpréteur.

echo([:{:@(#~*)10&#.inv@*)/1+i.".>{:ARGV

Voici une explication:

  • x #. yinterprète le vecteur entier ycomme un xnombre de base ; par exemple, les 10 #. 1 2 3 4rendements 1234.
  • u inv donne le inverse d'un verbe u. En particulier, x #. inv yreprésente ycomme un xnombre de base ; par exemple, les 10 #. 1234rendements 1 2 3 4. Notez que cela invest défini comme ^:_1, c'est-à-direu appliqué -1 fois.
  • x * yest le produit de xet donne yainsi x 10&#.inv@* yune représentation en base 10 du produit de xet y.
  • x # ycopie le n élément -ième yaussi souvent que le n ième élément de x; when xest un vecteur de booléens, xsélectionne les éléments yà prendre. Par exemple, les 1 0 1 0 # 1 2 3 4rendements 1 3.
  • * ydonne le signal dey .
  • x u~ yest le réflexe de u, c'est-à-dire le même quey u x .
  • Ainsi, y #~ * ydonne un vecteur de tous les éléments ypositifs. En notation tacite, cela peut être écrit avec un crochet comme (#~ *).
  • {: y renvoie le dernier élément de y .
  • assemblés ensemble, nous obtenons la phrase tacite ([:{:@(#~*)10&#.inv@*).
  • u/ yest la réduction du yverbe dyadique uinséré entre les éléments dey . Par exemple, +/1 2 3 4est comme 1 + 2 + 3 + 4et donne10 .
  • Ainsi, la phrase ([:{:@(#~*)10&#.inv@*)/ ydonne le dernier chiffre du produit des articles de y.
  • ARGV est un vecteur encadré des arguments de la ligne de commande.
  • ".>{:ARGV est le dernier argument non encadré et interprété comme un nombre.
  • i. ycalcule les nombres naturels de 0ày - 1 .
  • Ainsi, 1+i. ydonne des nombres naturels de 1à y. J'aurais pu aussi utiliser >: incrément ici, mais 1+c'est plus clair au même prix que les caractères.
  • Le programme entier s'applique juste 1+i.".>{:ARGV(le vecteur de 1au nombre dans le dernier argument de la ligne de commande) au verbe ([:{:@(#~*)10&#.inv@*)/et imprime le résultat avec echo.

1

Pyt , 5 octets

!₫ą0⦋

Explication:

         Implicit input (n)
!        n!
 ₫       Reverse the digits of (n!) - this disregards leading zeroes after reversal
  ą      Convert to array of digits
   0⦋    Get the first element

Essayez-le en ligne!


1

R , 63 55 51 46 octets

Calcule la factorielle, extrait le dernier chiffre non nul. Merci à Giuseppe d'avoir fourni la structure de base.

(y=(gamma(scan()+1))%/%10^(0:1e5)%%10)[!!y][1]

Essayez-le en ligne!

Alternativement, mon ancienne réponse de 51 octets:

Calcule la factorielle, convertit en caractère, supprime tous les 0s, puis prend le caractère final. Enregistré 2 octets grâce à Giuseppe.

substring(x<-gsub("0","",gamma(scan())+1),nchar(x))

Essayez-le en ligne!


1
gamma(x+1)est plus court quefactorial(x)
Giuseppe

sans conversion de chaîne, le meilleur que j'ai réussi à obtenir était (y=(x<-gamma(scan()+1))%/%10^(0:nchar(x))%%10)[!!y][1]de 54 octets.
Giuseppe

@Giuseppe Nous pouvons remplacer nchar(x)par 1e5une solution de 46 octets! Bien joué.
rturnbull


1

Perl 6 ,  26  35 octets

{[*](1..$_)~~/.*<(<-[0]>/}

Essayez-le


En programme complet:

put [*](1..@*ARGS[0])~~/.*<(<-[0]>/

Essayez-le

Étendu:

{
  [*]( 1..$_ ) # reduce using &infix:« * »
  ~~           # match with
  /
    .*         # any number of values (so it matches from the end)
    <(         # only capture the following
    <-[0]>     # any value but 0 (negated character class)
  /
}

1

C (gcc) , 72 octets (fonction)

f(n,d)long long n,d;{for(d=1;n;d%=10000)for(d*=n--;d%10<1;d/=10);d%=10;}

Essayez-le en ligne!

C (gcc) , 101 99 octets (programme entier)

main(){long long n,d=1;for(scanf("%lld",&n);n;d%=10000)for(d*=n--;d%10<1;d/=10);printf("%d",d%10);}

Essayez-le en ligne!

Cette question a juste 8 ans, donc "machine raisonnable" n'est pas la même qu'à l'époque, mais j'obtiens des temps de ~ 0,01 seconde sur mon ordinateur lorsque je fais tous les cas de test ensemble, donc à moins que la vitesse des ordinateurs n'ait augmenté par un facteur de 1000 cette dernière décennie, ça devrait aller.


La loi de Moore tient toujours (un peu), donc elle devrait être environ 16 fois plus rapide
ASCII uniquement le

En outre, une fonction est très bien
uniquement le


0

Attaché , 26 octets

Last@`\&:(All@V)@Digits@`!

Essayez-le en ligne!

Explication

Last@`\&:(All@V)@Digits@`!

Il s'agit d'une composition de 4 fonctions:

  • `! - c'est une version fonctionnelle de l'opérateur factoriel
  • Digits - cela obtient les chiffres de la factorielle
  • \&:(All@V)- Il s'agit d'une fonction de sélection. Il fonctionne en liant à gauche ( &:) la fonction All@Và \, qui est select. À son tour, All@Vest un moyen rapide de tester si un nombre n'est pas 0. Il fonctionne en transposant son entrée dans un vecteur0 -> [0] puis en demandant si tous ces membres sont véridiques (c'est-à-dire pas 0). Cela donne les chiffres du nombre sans 0.
  • Last - cela obtient simplement le dernier membre de ce tableau.

Cela semble incroyablement lent - le TIO a expiré (1 minute) sur le cas de test 100000 - comment avez-vous obtenu le résultat 1000000 en 10 secondes?
Toby Speight

@TobySpeight Lorsque j'ai répondu à ce défi, cette exigence particulière n'était pas là (consultez l'historique des révisions).
Conor O'Brien

Ah, j'aurais dû regarder l'histoire! Vous avez bien vérifié tous les cas de test dans la question?
Toby Speight

Il semble qu'il y ait eu une vague de réponses au cours de la période pendant laquelle le délai a été supprimé de la question - c'est vraiment dommage, vraiment.
Toby Speight

@TobySpeight Oui, je l'ai fait. C'est malheureux et je ne suis pas sûr de la politique à ce sujet.
Conor O'Brien

0

APL (Dyalog Unicode) , 18 15 octets

{⊢/⍵/⍨0≠⍎¨⍵}⍕∘!

Essayez-le en ligne!

Fonction de préfixe tacite. Renvoie le chiffre correct pour un seul cas de test ou une chaîne de chiffres pour plusieurs cas de test.

Merci à @ Adám et @ErikTheOutgolfer pour 3 octets chacun.

Comment?

{⊢/⍵/⍨0≠⍎¨⍵}⍕∘!  Main function. Argument is a number following the !.
              !  Factorial
                then
                Format (stringify)
        ⍎¨⍵}     Execute (turn to number) each digit of the argument
      0         Check if each is 0. This returns a boolean vector
                Swap arguments for the following fn/op
   ⍵/            Replicate. This takes a boolean vector as left arg and returns the truthy elements of the right arg. E.g.: 1 1 0/1 2 3  1 2.
{⊢/              Reduce. This returns the rightmost (last) element of a vector argument.

0

APL NARS, 28 octets, 14 caractères

{↑≠v/v←⌽⍎¨⍕!⍵}

Je ne sais pas pourquoi mais cela passe le test:

  q←{↑≠v/v←⌽⍎¨⍕!⍵}       
  q¨1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 6 4 2 2 4 2 8 8 8 6 8 2 

0

AWK , 47 57 octets

{for(p=$1;--$1;p=(p*$1)%1e4)while(!(p%10))p/=10;$0=p%10}1

Essayez-le en ligne!

La solution d'origine ne gérait pas très bien les "grandes" valeurs d'entrée. Cela pourrait ajouter -Mà le forcer à fonctionner, mais cela nécessite également beaucoup plus de temps de traitement.


Ouais, @TobySpeight, infça ne va pas %très bien. :(
Robert Benson

Ah ... en regardant la version de la question à laquelle j'ai répondu, de grands nombres n'étaient pas nécessaires.
Robert Benson

-2

Japt , 6 octets

Je suis venu avec quelques 6 octets différents mais j'ai préféré celui-ci. Je suis convaincu qu'il doit y avoir un moyen de le faire en 5, cependant.

Êsw ìv

Essayez-le


Explication

Êcalcule la factorielle de l'entrée, la sconvertit en chaîne et revient en entier après l' wavoir inversée, ìconvertit le résultat en un tableau de chiffres et vrenvoie le premier élément.


Alternatives

Êì w æ
ÊìÈf Ì
Êì f o
Êsw sg
Êìf ìo
Êìf ìÌ

Combien de temps cela prend-il pour exécuter tous les cas de test?
Toby Speight

@TobySpeight; c'est très facile à tester en suivant le lien pour l'essayer. Notez que les 4 derniers cas de test échoueront car leurs factorielles sont plus grandes que l'entier max de JavaScript.
Shaggy

Donc ça ne résout pas vraiment le problème alors? La question dit qu'elle doit réussir pour 1 ≤ N ≤ 1 000 000 . D'autres réponses démontrent que vous n'avez pas besoin de pouvoir stocker la factorielle pour calculer la réponse.
Toby Speight

J'ai essayé le test en ligne, mais il expire sur le premier cas de test que j'ai essayé (1000).
Toby Speight

-2

Perl 5 , 36 + 10 ( -p -Mbigint) = 46 octets

$"=$_;$_*=$"while$"-=1;($_)=/(.)0*$/

Essayez-le en ligne!


La version TIO échoue aux deux premiers cas de test que j'ai essayés: 1000000 ⇒ f(devrait être 4 ) et 100 ⇒ 7(devrait être 4 )
Toby Speight

Il déborde de la taille d'un int. La nouvelle version fonctionne en utilisant bigint. Les performances laissent encore à désirer car il s'agit d'un calcul de force brute. Cela signifie qu'il expire sur TIO pour un plus grand nombre.
Xcali
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.