Pseudofactoriel


39

Il existe un nombre plutôt curieux qui apparaît parfois dans les problèmes de mathématiques ou les énigmes. Le pseudofactoriel (N) est le plus petit commun multiple des nombres 1 à N; en d'autres termes, c'est le nombre le plus bas qui contient tous les nombres de 1 à N en tant que facteurs.

Par exemple, pseudofactorial (7) = 3 * 4 * 5 * 7, ce qui correspond à 7! sauf que 2 et 6 ont été supprimés car ils sont contenus dans d'autres termes.

Ecrivez un programme pour calculer pseudofactoriel (N) et, comme toujours, le code le plus court gagne.

Voici une courte liste pour votre usage. Vous trouverez plus de cas de test dans l’OEIS sous A003418 .

Factorielle:

  1. 1
  2. 2
  3. 6
  4. 24
  5. 120
  6. 720
  7. 5040

Pseudofactorial:

  1. 1
  2. 2
  3. 6
  4. 12
  5. 60
  6. 60
  7. 420

6
Je ne suis pas sûr de comprendre pourquoi 2et 6ont été retirés de la liste des multiples. Pouvez-vous s'il vous plaît clarifier les règles?
Maltysen

2
@Mattysen, psuedofactorial (N) est le plus petit nombre dont les facteurs sont compris entre 1 et N (Le plus petit commun multiple de ces nombres). Telle est la définition technique, mais la façon dont je l’écrivais laissait entendre qu’elle ressemblait à une factorielle.
Tony Ruth


4
Bienvenue dans Programming Puzzles & Code Golf! C'est un beau premier challenge!
Alex A.

1
Votre premier défi est arrivé au sommet de HNQ. Agréable!
Daniel M.

Réponses:




8

C (avec x86), 52 octets

d(n,k,b,t){for(b=k=1;b;++k)for(t=n,b=0;t;b+=k%t--);}

Vérifie les nombres à partir de 1. Pour chaque nombre, divisez-le par tous les nombres de n à 1 et additionnez les autres. S'arrête quand la somme est 0.

Usage:

main()
{
    printf("%d\n", d(7)); // outputs 420
}

Il n’est pas évident de savoir comment il renvoie une valeur (il n’existe pas return énoncé).

La convention d'appel pour x86 indique que la fonction doit renvoyer sa valeur dans le eaxregistre. De manière pratique, l’instruction de division idivattend son entrée dans eaxet produit le résultat dans eax(quotient) et edx(reste). La dernière itération est divisée kpar 1, eaxelle contiendra donc la bonne valeur lorsque la fonction sera fermée.

Cela ne fonctionne que lorsque l'optimisation est activée (en mode débogage, elle est affichée 421).


Comment vous en sortir en ne déclarant pas le type de n, k, b et t?
Tony Ruth

C a la règle default-int - tous les types omis sont intpar défaut (y compris la valeur de retour). Cela fonctionne pour les arguments de fonction s'ils sont déclarés en utilisant la syntaxe dite "à l'ancienne". La déclaration avec des types explicitement définis seraitint d(n,k,b,t) int n,k,b,t; {...}
anatolyg

si vous profitez d'une convention d'appel, alors cela devrait vraiment être marqué "C (cdecl)" plutôt que simplement "C"
Steve Cox -

@SteveCox Les deux cdeclet stdcallutilisent la même méthode pour la valeur de retour, donc je suppose que cela x86suffit
anatolyg

7

Haskell, 20 octets

f x=foldr1 lcm[1..x]

Exemple d'utilisation: map f [1..7]-> [1,2,6,12,60,60,420].

Le lcmtruc à Haskell.


6

Python + SymPy, 45 octets

import sympy
lambda n:sympy.lcm(range(1,n+1))

Assez explicite.


Python 2, 57 54 octets

i=r=input();exec't=r\nwhile r%i:r+=t\ni-=1;'*r;print r

Testez-le sur Ideone .

Comment ça marche

L'entrée est stockée dans les variables i et r .

execexécute le code suivant r fois.

t=r
while r%i:r+=t
i-=1

Bien que i varie de r à 1 , nous ajoutons la valeur initiale de r (stockée dans t ) autant de fois que nécessaire pour que r se crée un multiple de i . Le résultat est évidemment un multiple de t .

La valeur finale de r est donc un multiple de tous les entiers compris dans l'intervalle [1, ..., n] , où n est l'entrée.


1
Sans utiliser de bibliothèques tierces ou d’ execastuces, il existe une solution de 78 octets: from fractions import*;lambda n:reduce(lambda x,y:x*y/gcd(x,y),range(1,n+1),1) Utilise le fait que lcm(x,y) = x*y/gcd(x,y).
Bakuriu

6

Python, 46 octets

g=lambda n,c=0:n<1or(c%n<1)*c or g(n,c+g(n-1))

Vous recherchez le multiple cde g(n-1)directement. Je pensais auparavant que cette méthode trouverait à tort que 0 est un multiple de quoi que ce soit, mais que le orcourt-circuit soit (c%n<1)*cignoré c==0, car 0 correspond à Falsey.


50 octets:

g=lambda n,i=1:n<1or(i*n%g(n-1)<1)*i*n or g(n,i+1)

Comme la solution de Dennis , mais comme une fonction récursive. Après avoir calculé g(n-1), cherche le plus petit multiple i*nde nqui est aussi un multiple deg(n-1) . Vraiment lent.

Merci à Dennis pour 4 octets en regardant des multiples de nau lieu de g(n-1).


5

J, 9 octets

[:*./1+i.

Approche directe. Crée la plage de nombres [0, ..., n-1], puis en ajoute un à chacun et la réduit à l'aide du LCM.

Usage

   f =: [:*./1+i.
   f 7
420


4

Mathematica, 13 octets

LCM@@Range@#&

N'est-ce pas équivalent à composer LCMet Rangeavec @*?
Maltysen

1
LCMopère élément par élément sur une liste, qui serait passée Range, ce qui veut dire que ceci renverrait simplement le lcm ( x ) pour x de 1 à n . En outre, il manque un élément &qui fermerait la fonction anonyme. Quelque chose comme LCM@@Range@#&pour 13 octets fonctionnerait.
miles


3

Pyth - 8 octets

Vérifie tous les nombres jusqu'à ce qu'il en trouve un qui soit divisible par [1..N].

f!s%LTSQ

Suite de test .


3

Octave, 27 octets

@(x)lcm(1,num2cell(1:x){:})

Crée une fonction anonyme pouvant être appelée ans(N).

Démo en ligne

Explication

Cette solution crée une liste de tous les nombres entre 1and x( 1:x), les convertit en tableau de cellules avec num2cell. Ensuite, l' {:}indexation crée une liste séparée par des virgules qui est transmise à lcmplusieurs arguments d'entrée pour calculer le plus petit commun multiple. Un 1 est toujours passé en tant que premier argument lcmcar lcmil nécessite toujours au moins deux arguments en entrée.


1
Donc lcmdans Octave accepte plus de 2 entrées! Intéressant
Luis Mendo

@LuisMendo Yup 2+
Suever

3

MATLAB, 49 octets

@(x)find(~any(bsxfun(@rem,1:prod(1:x),(1:x)')),1)

+1 pourbsxfun
flawr

3

Perl 6 , 13 octets

{[lcm] 1..$_}

Bloc de code anonyme qui crée une plage de 1 à l'entrée (incluse), puis réduit celle-ci avec &infix:<lcm>.

Exemple:

#! /usr/bin/env perl6
use v6.c;

my &postfix:<p!> = {[lcm] 1..$_}

say 1p!; # 1
say 2p!; # 2
say 3p!; # 6
say 4p!; # 12
say 5p!; # 60
say 6p!; # 60
say 7p!; # 420

say 10000p!; # 5793339670287642968692270879...
# the result from this is 4349 digits long


2

JavaScript (ES6), 92 88 80 74 69 octets:

Merci @ConorOBrien et @Neil

y=>(g=(a,b)=>b?g(b,a%b):a,[...Array(y)].map((_,i)=>y=y*++i/g(y,i)),y)

b?g(b,a%b):aenregistre un octet.
Neil

y*++i/g(y,i)enregistre quelques octets supplémentaires.
Neil

1

05AB1E, 20 octets

Lpvyi¹LÒN>¢àN>*ˆ}}¯P

Explication

Lpv                    # for each item in isprime(range(1,N)): N=7 -> [0,1,1,0,1,0,1]
   yi                  # if prime
     ¹LÒN>¢            # count occurrences of the prime 
                         in the prime-factorization of range(1,N):
                         p=2 -> [0,1,0,2,0,1,0]
           àN>*ˆ       # add max occurrence of that prime multiplied by the prime 
                         to global array: N=7 -> [4,3,5,7]
                }}     # end if/loop
                  ¯P   # get product of global array

Essayez-le en ligne


1

Minkolang 0,15 , 12 octets

J'ai deux solutions de 12 octets et les ai incluses toutes les deux.

1n[i1+4$M]N.

Essayez-le ici!

Explication

1               Push 1
 n              Take number from input
  [             For loop that repeats n times
   i1+          Push loop counter + 1
      4$M       Pop b, a and push lcm(a,b)
         ]      Close for loop
          N.    Output as number and stop.

À peu près aussi simple que possible.


11nLd[4$M]N.

Essayez-le ici!

Explication

11              Push two 1s
  n             Take number from input
   L            Pop b, a and push range from a to b, inclusive
    d           Duplicate top of stack (n)
     [4$M]      Pop b, a and push lcm(a,b), n times
          N.    Output as number and stop.

Une troisième solution peut en être dérivée: supprimer un 1et ajouter un daprès le courant d. Dans les deux cas, le nombre supplémentaire est nécessaire car la boucle for s'exécute une fois de trop et que l'exécuter une fois de moins prend deux octets ( 1-juste avant le [).


1

Ruby, 25 octets

g=->n{(1..n).reduce :lcm}

Ruby, 25 octets

g=->n{n<1?1:a[n-1].lcm n}

1
Bonjour et bienvenue chez PPCG! Excellent premier post! Vous n'êtes pas obligé de nommer votre fonction, vous pouvez donc la supprimer g=.
NoOneIsHere

Les fonctions anonymes sont autorisées.
Erik l'Outgolfer

1

Langue GameMaker, 60 octets

for(b=k=1;b;++k){b=0for(t=argument0;t;b+=k mod t--)}return k

Basé sur la logique de la réponse d'Anatolyg.


1

PHP, 61 52 48 octets

enregistré 9 octets grâce à @ user59178, 4 octets en fusionnant les boucles.

La récursion en PHP est volumineuse à cause du functionmot clé; donc j'utilise l'itération.
Et avec quelques "petits" tricks, j'ai même maintenant battu le JS d'Arnauld .

while(++$k%++$i?$i>$argv[1]?0:$i=1:$k--);echo$k;

prend en entrée l'argument de la ligne de commande. Courir avec-r .

panne

while(++$k%++$i?    # loop $i up; if it does not divide $k
    $i>$argv[1]?0       # break if $i (smallest non-divisor of $k) is larger than input
    :$i=1               # while not, reset $i and continue loop with incremented $k
    :$k--);         # undo increment while $i divides $k
echo$k;         # print $k

non-golfé

C'est en fait deux boucles en une:

while($i<=$argv[1]) # loop while $i (smallest non-divisor of $k) is not larger than input
    for($k++,       # loop $k up from 1
        $i=0;$k%++$i<1;);   # loop $i up from 1 while it divides $k
echo$k;             # print $k

Note: copié de ma réponse sur le duplicata




0

Hoon , 67 octets

|*
*
(roll (gulf 1 +<) |=({a/@ b/_1} (div (mul a b) d:(egcd a b))))

Créez la liste [1..n], repliez-la sur lcm. Malheureusement, Hoon stdlib ne dispose pas d'un logiciel pré-construit que je peux utiliser: /



0

AWK, 42 octets

{for(x=n=1;n<=$1;)if(x%n++){x++;n=1}$0=x}1

Utilisation en ligne de commande:

awk '{for(x=n=2;n<=$1;)if(x%n++){x++;n=2}$0=x}1' <<< NUM

Je n'ai pas vu de AWKsolution et un duplicata de la question vient d'être posté hier, alors j'ai pensé jeter cela ensemble. La résolution est plutôt lente pour 19ou plus grande sur ma boîte, mais cela fonctionne.


0

CQIB , 35 32 octets

Cela m'a amené ici.

:{p=0[a|~q%b|p=1]]~p=0|_Xq\q=q+1

Explication:

:        Get cmd line param as number 'a'
{        Start an infinite DO loop
p=0      Sets a flag that shows if divisions failed
[a|      FOR (b=1; b<=a; b++)
~q%b     IF 'q' (which starts at 1 in QBIC) is not cleanly divisible by 'b'
|p=1     THEN Set the flag
]]   Close the FOR loop and the IF, leave the DO open
~p=0     IF 'q' didn't get flagged
|_Xq     THEN quit, printing 'q'
\q=q+1   ELSE raise 'q', redo
         [DO Loop implicitly closed by QBIC]

Voici une version qui arrête de tester qquand bne pas le diviser proprement. En outre, l'ordre d'essai best contre qest inversée dans l'hypothèse que la hausse b's seront plus difficiles à diviser par (prendre 2, 3, 4par exemple: si %2=0,%4 pourrait être !0. Réciproquement pas tant ...).

:{p=0[a,2,-1|~q%b|p=1┘b=2]]~p=0|_Xq\q=q+1



0

8ème , 23 octets

Code

1 ' lcm rot 2 swap loop

Ce code laisse pseudofactorial résultant sur TOS

Usage et exemple

ok> 7 1 ' lcm rot 2 swap loop .
420

Ou plus clairement

ok> : pseudofact 1 ' n:lcm rot 2 swap loop ;

ok> 7 pseudofact .
420
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.