Pseudofactorial


39

C'è un numero piuttosto curioso che compare a volte in problemi di matematica o indovinelli. Lo pseudofattoriale (N) è il minimo comune (cioè il più basso) multiplo dei numeri da 1 a N; in altre parole, è il numero più basso che ha tutti i numeri da 1 a N come fattori.

Ad esempio pseudofactorial (7) = 3 * 4 * 5 * 7, che è lo stesso di 7! tranne che 2 e 6 sono stati rimossi perché contenuti in altri termini.

Scrivi un programma per calcolare pseudofattoriale (N) e come sempre vince il codice più corto.

Ecco un breve elenco per il tuo uso. Altri casi di test sono disponibili nell'OEIS alla voce A003418 .

Fattoriale:

  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
Non sono sicuro di capire perché 2e 6sono stati rimossi dall'elenco dei multipli. Potete per favore chiarire le regole?
Maltysen,

2
@Mattysen, psuedofactorial (N) è il numero più piccolo che ha i numeri da 1 a N come fattori (il minimo comune multiplo di quei numeri). Questa è la definizione tecnica, ma il modo in cui l'ho scritta mi ha suggerito in qualche modo che è simile a un fattoriale.
Tony Ruth,


4
Benvenuto in Programmazione di puzzle e codice golf! Questa è una bella prima sfida!
Alex A.

1
La tua prima sfida è arrivata al vertice di HNQ. Bello!
Daniel M.

Risposte:




8

C (con x86), 52 byte

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

Controlla i numeri da 1 in su. Per ogni numero, lo divide per tutti i numeri da n a 1 e somma i rimanenti. Si interrompe quando la somma è 0.

Uso:

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

Non è ovvio come restituisca un valore (non esiste alcuna returnistruzione).

La convenzione di chiamata per x86 afferma che la funzione deve restituire il suo valore nel eaxregistro. Convenientemente, l'istruzione di divisione idivprevede il suo input in eaxe genera il risultato in eax(quoziente) e edx(resto). L'ultima iterazione si divide kper 1, quindi eaxconterrà il valore corretto all'uscita dalla funzione.

Funziona solo con le ottimizzazioni attivate (in modalità debug, genera 421).


Come fai a non dichiarare il tipo di n, k, b e t?
Tony Ruth,

C ha la regola di default-int - tutti i tipi omessi sono intdi default (incluso il valore di ritorno). Funziona con argomenti di funzione se vengono dichiarati usando la cosiddetta sintassi "vecchio stile". La dichiarazione con tipi esplicitamente definiti sarebbeint d(n,k,b,t) int n,k,b,t; {...}
anatolyg

se stai approfittando di una convenzione di chiamata, allora questo dovrebbe davvero essere contrassegnato "C (cdecl)" piuttosto che solo "C"
Steve Cox,

@SteveCox Entrambi cdecle stdcallusano lo stesso metodo per restituire il valore, quindi immagino x86sia sufficiente
anatolyg

7

Haskell, 20 byte

f x=foldr1 lcm[1..x]

Esempio di utilizzo: map f [1..7]-> [1,2,6,12,60,60,420].

Il lcmtrucco di Haskell.


6

Python + SymPy, 45 byte

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

Abbastanza autoesplicativo.


Python 2, 57 54 byte

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

Provalo su Ideone .

Come funziona

L'ingresso è memorizzato nelle variabili i e r .

execesegue il seguente codice r volte.

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

Mentre i varia da r a 1 , aggiungiamo il valore iniziale di r (memorizzato in t ) tutte le volte necessarie a r stesso per creare un multiplo di i . Il risultato è, ovviamente, un multiplo di t .

Il valore finale di r è quindi un multiplo di tutti i numeri interi nell'intervallo [1, ..., n] , dove n è l'input.


1
Senza usare librerie o exectrucchi di terze parti esiste una soluzione da 78 byte: from fractions import*;lambda n:reduce(lambda x,y:x*y/gcd(x,y),range(1,n+1),1) utilizza il fatto lcm(x,y) = x*y/gcd(x,y).
Bakuriu,

6

Python, 46 byte

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

Alla ricerca del multiplo cdi g(n-1)direttamente. Prima avevo però che questo metodo avrebbe erroneamente trovato 0 come multiplo di qualsiasi cosa, ma il orcortocircuito o (c%n<1)*csalterà c==0anche perché 0 è Falsey.


50 byte:

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

Come la soluzione di Dennis , ma come funzione ricorsiva. Dopo aver calcolato g(n-1), cerca il più piccolo multiplo i*ndi nquello che è anche un multiplo di g(n-1). Davvero lento.

Grazie a Dennis per 4 byte guardando i multipli di ninvece di g(n-1).


5

J, 9 byte

[:*./1+i.

Approccio diretto. Crea l'intervallo di numeri [0, ..., n-1], quindi ne aggiunge uno a ciascuno e lo riduce utilizzando LCM.

uso

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

5

MATL , 4 byte

:&Zm

Provalo online!

Spiegazione

:      % Take input N implicitly. Generate range [1 2 ... N]
&Zm    % LCM of the numbers in that array. Display implicitly

4

Mathematica, 13 byte

LCM@@Range@#&

non equivale a comporre LCMe Rangecon @*?
Maltysen,

1
LCMfunziona in modo elementale su un elenco, che verrebbe passato Range, nel senso che ciò restituirebbe semplicemente lcm ( x ) per x da 1 a n . Inoltre, manca un elemento &che potrebbe chiudere la funzione anonima. Qualcosa come LCM@@Range@#&per 13 byte funzionerebbe.
miglia


3

Pyth - 8 byte

Controlla tutti i numeri fino a quando non ne trova uno divisibile per [1..N].

f!s%LTSQ

Test Suite .


3

Ottava, 27 byte

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

Crea una funzione anonima che può essere invocata come ans(N).

Demo online

Spiegazione

Questa soluzione crea un elenco di tutti i numeri tra 1e x( 1:x), li converte in un array di celle con num2cell. Quindi l' {:}indicizzazione crea un elenco separato da virgole che viene passato lcmcome più argomenti di input per calcolare il minimo comune multiplo. Un 1 viene sempre passato come primo argomento lcmperché lcmrichiede sempre almeno due argomenti di input.


1
Quindi lcmin Octave accetta più di 2 input! Interessante
Luis Mendo il

@LuisMendo Yup 2+
Suever,

3

MATLAB, 49 byte

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

+1 perbsxfun
flawr

3

Perl 6 , 13 byte

{[lcm] 1..$_}

Blocco di codice anonimo che crea un intervallo da 1 all'input (incluso) e quindi lo riduce con &infix:<lcm> .

Esempio:

#! /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 byte:

Grazie @ConorOBrien e @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):asalva un byte.
Neil,

y*++i/g(y,i)salva qualche altro byte.
Neil,

1

05AB1E, 20 byte

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

Spiegazione

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

Provalo online


1

Minkolang 0.15 , 12 byte

Ho due soluzioni a 12 byte e le ho incluse entrambe.

1n[i1+4$M]N.

Provalo qui!

Spiegazione

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.

Più semplice che mai.


11nLd[4$M]N.

Provalo qui!

Spiegazione

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.

Da ciò può derivare una terza soluzione: rimuovere a 1e aggiungere a ddopo la corrente d. In entrambi i casi, il numero aggiuntivo è necessario perché il ciclo for viene eseguito troppe volte e per eseguirlo una volta in meno sono necessari due byte ( 1-appena prima di [).


1

Rubino, 25 byte

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

Rubino, 25 byte

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

1
Ciao e benvenuto in PPCG! Ottimo primo post! Non è necessario assegnare un nome alla funzione, quindi è possibile rimuoverla g=.
NoOneIsHere il

Sono ammesse funzioni anonime.
Erik the Outgolfer,

1

Lingua GameMaker, 60 byte

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

Basato sulla logica della risposta di Anatolyg.


1

PHP, 61 52 48 byte

salvato 9 byte grazie a @ user59178, 4 byte unendo i loop.

La ricorsione in PHP è voluminosa a causa della functionparola chiave; quindi uso l'iterazione.
E con alcuni "piccoli" trucchi, ora ho persino battuto il JS di Arnauld .

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

accetta input dall'argomento della riga di comando. Corri con -r.

abbattersi

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

ungolfed

In realtà sono due loop in uno:

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

Nota: copiato dalla mia risposta sul duplicato



0

Pyke, 3 byte, non competitivo

S.L

Provalo qui!

S   - range(1, input+1)
 .L - lowest_common_multiple(^)

0

Hoon , 67 byte

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

Crea l'elenco [1..n], piega l'elenco con mcm. Sfortunatamente, Hoon stdlib non ne ha uno pre-costruito che posso usare: /



0

AWK, 42 byte

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

Utilizzo della riga di comando:

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

Non ho visto una AWKsoluzione e un duplicato della domanda è stato pubblicato ieri, quindi ho pensato di metterlo insieme. È piuttosto lento per risolvere 19o più grande sulla mia scatola, ma funziona.


0

QBIC , 35 32 byte

Questo mi ha portato qui.

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

Spiegazione:

:        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]

Ecco una versione che interrompe il test qquando bnon la divide in modo chiaro. Inoltre, l'ordine di testare b's contro qè invertito nel presupposto che più alti b' s sarà più difficile da dividere per (prendere 2, 3, 4per esempio: se %2=0, %4potrebbe essere !0. Viceversa non tanto ...).

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



0

8 , 23 byte

Codice

1 ' lcm rot 2 swap loop

Questo codice lascia pseudofattoriale risultante su TOS

Uso ed esempio

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

O più chiaramente

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

ok> 7 pseudofact .
420
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.