Calcola la funzione di Eulero


27

sfondo

La funzione totulistica di Eulero φ(n)è definita come il numero di numeri interi minori o uguali a quelli nche sono relativamente primi n, cioè il numero di possibili valori di xin 0 < x <= nper i quali gcd(n, x) == 1. Abbiamo avuto un paio totient - relative sfide , ma mai uno che è solo calcolo.

La mappatura della funzione totient sui numeri interi è OEIS A000010 .

Sfida

Dato un numero intero n > 0, calcola φ(n). È possibile accettare input tramite argomenti della riga di comando, input standard, argomenti di funzioni o qualsiasi altra cosa ragionevole. È possibile fornire output tramite output standard, valori di ritorno o qualsiasi altra cosa ragionevole. Le funzioni anonime sono accettabili. È possibile supporre che l'input non superi il metodo naturale di memorizzazione di numeri interi, ad esempio intin C, ma è necessario supportare input fino a 255. Se la propria lingua ha una funzione di totient incorporata, non è possibile utilizzarla.

Esempi

φ(1) => 1
φ(2) => 1
φ(3) => 2
φ(8) => 4
φ(9) => 6
φ(26) => 12
φ(44) => 20
φ(105) => 48

Vince la risposta più breve in byte. Se la tua lingua utilizza una codifica diversa da UTF-8, menzionala nella tua risposta.


4
Beh, ci fu questo l'altro giorno. Non penso che l'applicazione ripetuta faccia una differenza sufficiente, ma semmai chiuderei l'altra, perché non penso che l'applicazione ripetuta aggiunga qualcosa. Detto questo, la differenza più grande è che uno ha permesso i built-in e questo no.
Martin Ender,

La proibizione dei built-in apparentemente non ha alcun impatto sulle risposte.
Julie Pelletier,

2
@JuliePelletier Perché è quello? In caso contrario, la mia risposta a Mathematica sarebbe stata inferiore di 19 byte:EulerPhi
Martin Ender il

@JuliePelletier GCD è consentito perché il calcolo del GCD non è il problema previsto da risolvere. Certo, potrebbe aumentare il conteggio dei byte su queste risposte, ma non migliora la sfida. Modificherò per chiarire.
Bkul

Risposte:


13

Mathematica, 27 22 byte

Range@#~GCD~#~Count~1&

Una funzione senza nome che accetta e restituisce un numero intero.

Non c'è molto da spiegare qui, tranne che @è notazione con prefisso per chiamate di funzione ed ~...~è notazione con infisso (associativa sinistra), quindi quanto sopra è lo stesso di:

Count[GCD[Range[#], #], 1] &

11

MATL, 7 byte

t:Zd1=s

Puoi provarlo online . Idea più semplice, crea un vettore da 1 a N e prendi gcd di ogni elemento con N ( Zdfa gcd). Quindi, trova quali elementi sono uguali a 1 e somma il vettore per ottenere la risposta.


L'integrato è _Zpper quelli che si chiedono.
David,

11

J, 9 byte

(-~:)&.q:

Questo si basa sul saggio di Jsoftware sulle funzioni complete .

Dato n = p 1 e 1p 2 e 2 ∙∙∙ p k e k in cui p k è un fattore primo di n , la funzione totiente φ ( n ) = φ ( p 1 e 1 ) ∙ φ ( p 2 e 2 ) ∙∙∙ φ ( p k e k ) = ( p 1 - 1) p 1 e 1 - 1 ∙ ( p 2 - 1) p 2e 2 - 1 ∙∙∙ ( p k - 1) p k e k - 1 .

uso

   f =: (-~:)&.q:
   (,.f"0) 1 2 3 8 9 26 44 105
  1  1
  2  1
  3  2
  8  4
  9  6
 26 12
 44 20
105 48
   f 12345
6576

Spiegazione

(-~:)&.q:  Input: integer n
       q:  Prime decomposition. Get the prime factors whose product is n
(   )&     Operate on them
  ~:         Nub-sieve. Create a mask where 1 is the first occurrence
             of a unique value and 0 elsewhere
 -           Subtract elementwise between the prime factors and the mask
     &.q:  Perform the inverse of prime decomposition (Product of the values)

Usa il fatto che il totient è moltiplicativo per creare un'altra soluzione in J usando la ricorsione :)
Leaky Nun

@LeakyNun Non credo che ci sia un modo semplice per giocare a golf nel factoring, dato che anche usare la forma iterativa ha [:*/@({.(^-(^<:)){:)2&p:bisogno di 24 byte, anche usando l'integrato per ottenere i numeri primi e i loro esponenti. O forse c'è un modo più breve e non lo vedo.
miglia

8

Gelatina, 4 byte

Rgċ1

Provalo online!

Spiegazione

Rgċ1   Main monadic chain. Argument: z

R      Yield [1 2 3 .. z].
 g     gcd (of each) (with z).
  ċ1   Count the number of occurrences of 1.

Con incorporato

ÆṪ

Provalo online!

Spiegazione

ÆṪ   Main monadic chain. Argument: z

ÆṪ   Totient of z.

8

Haskell, 28 byte

f n=sum[1|1<-gcd n<$>[1..n]]

Usa Haskell's corrispondenza di costanti di . I trucchi qui sono abbastanza standard per il golf, ma spiegherò a un pubblico generale.

L'espressione è gcd n<$>[1..n]mappata gcd nsu [1..n]. In altre parole, calcola il gcdcon ndi ciascun numero da 1a n:

[gcd n i|i<-[1..n]]

Da qui, l'output desiderato è il numero di 1voci, ma Haskell non ha una countfunzione. Il modo idiomatico filterdi mantenere solo quello 1e prendere il risultato length, che è troppo lungo per il golf.

Al contrario, filterviene simulato da una comprensione dell'elenco [1|1<-l]con l'elenco risultante l. Di solito, le comprensioni degli elenchi associano i valori alla variabile come in [x*x|x<-l], ma Haskell consente di far corrispondere uno schema, in questo caso la costante 1.

Quindi, [1|1<-l]generando un 1su ogni corrispondenza di 1, estraendo efficacemente solo quelli 1dell'elenco originale. Chiamarlo sumdà la sua lunghezza.


Penso che questa sia la prima risposta di Haskell che effettivamente capisco. È un linguaggio così bello, ma è così diverso dalla maggior parte degli altri.
bkul,

Wow, mi aspettavo che la corrispondenza dei modelli dovesse essere esaustiva nelle liste di comprensione. Grazie per il trucco.
Damien,

8

Python 2, 44 byte

f=lambda n,d=1:d/n or-f(d)*(n%d<1)-~f(n,d+1)

Meno golf:

f=lambda n:n-sum(f(d)for d in range(1,n)if n%d<1)

Utilizza la formula di cui i totienti di Eulero dei divisori nhanno una somma di n:

enter image description here

Il valore di ϕ(n)può quindi essere calcolato ricorsivamente come nmeno la somma sui divisori non banali. In effetti, questo sta facendo inversione di Möbius sulla funzione identità. Ho usato lo stesso metodo in un golf per calcolare la funzione Möbius .

Grazie a Dennis per aver salvato 1 byte con un case base migliore, diffondendo il valore iniziale +nin +1per ciascuno dei nloop, fatto come -~.


6

Pyke, 5 byte

m.H1/

Provalo qui!

count(map(gcd, range(input)), 1)

1
Così tanti derivati ​​Python .. Mi piace questo però. Premessa interessante.
bkul

6

Regex (ECMAScript), 131 byte

Almeno -12 byte grazie a Deadcode (in chat)

(?=((xx+)(?=\2+$)|x+)+)(?=((x*?)(?=\1*$)(?=(\4xx+?)(\5*(?!(xx+)\7+$)\5)?$)(?=((x*)(?=\5\9*$)x)(\8*)$)x*(?=(?=\5$)\1|\5\10)x)+)\10|x

Provalo online!

L'output è la lunghezza della corrispondenza.

Le regex di ECMAScript rendono estremamente difficile contare qualsiasi cosa. Qualsiasi backref definito all'esterno di un loop sarà costante durante il loop, qualsiasi backref definito all'interno di un loop verrà ripristinato durante il looping. Pertanto, l'unico modo per portare lo stato attraverso iterazioni di loop è utilizzare la posizione di corrispondenza corrente. Questo è un singolo numero intero e può solo diminuire (beh, la posizione aumenta, ma la lunghezza della coda diminuisce, ed è ciò a cui possiamo fare matematica).

Date queste restrizioni, il semplice conteggio di interi coprimi sembra impossibile. Invece, usiamo la formula di Eulero per calcolare il totale.

Ecco come appare nello pseudocodice:

N = input
Z = largest prime factor of N
P = 0

do:
   P = smallest number > P that’s a prime factor of N
   N = N - (N / P)
while P != Z

return N

Ci sono due cose dubbie su questo.

Innanzitutto, non salviamo l'input, ma solo il prodotto corrente, quindi come possiamo arrivare ai fattori primi dell'input? Il trucco è che (N - (N / P)) ha gli stessi fattori primi> P di N. Potrebbe ottenere nuovi fattori primi <P, ma li ignoriamo comunque. Nota che questo funziona solo perché ripetiamo i fattori primi dal più piccolo al più grande, andando nell'altra direzione fallirebbe.

In secondo luogo, dobbiamo ricordare due numeri tra le iterazioni di loop (P e N, Z non contano poiché è costante) e ho appena detto che era impossibile! Per fortuna, possiamo far muovere quei due numeri in uno solo. Nota che, all'inizio del ciclo, N sarà sempre un multiplo di Z, mentre P sarà sempre inferiore a Z. Pertanto, possiamo solo ricordare N + P ed estrarre P con un modulo.

Ecco lo pseudo-codice leggermente più dettagliato:

N = input
Z = largest prime factor of N

do:
   P = N % Z
   N = N - P
   P = smallest number > P that’s a prime factor of N
   N = N - (N / P) + P
while P != Z

return N - Z

Ed ecco la regex commentata:

# \1 = largest prime factor of N
# Computed by repeatedly dividing N by its smallest factor
(?= ( (xx+) (?=\2+$) | x+ )+ )

(?=
        # Main loop!
        (
                # \4 = N % \1, N -= \4
                (x*?) (?=\1*$)

                # \5 = next prime factor of N
                (?= (\4xx+?) (\5* (?!(xx+)\7+$) \5)? $ )

                # \8 = N / \5, \9 = \8 - 1, \10 = N - \8
                (?= ((x*) (?=\5\9*$) x) (\8*) $ )

                x*
                (?=
                        # if \5 = \1, break.
                        (?=\5$) \1
                |
                        # else, N = (\5 - 1) + (N - B)
                        \5\10
                )
                x
        )+
) \10

E come bonus ...

Regex (ECMAScript 2018, numero di corrispondenze), 23 byte

x(?<!^\1*(?=\1*$)(x+x))

Provalo online!

L'output è il numero di corrispondenze. ECMAScript 2018 introduce look-behind a lunghezza variabile (valutato da destra a sinistra), che consente di contare semplicemente tutti i numeri coprimi con l'input.

Si scopre che questo è indipendentemente lo stesso metodo usato dalla soluzione Retina di Leaky Nun , e il regex ha persino la stessa lunghezza ( e intercambiabile ). Lo lascio qui perché potrebbe essere interessante che questo metodo funzioni in ECMAScript 2018 (e non solo in .NET).

                        # Implicitly iterate from the input to 0
x                       # Don’t match 0
 (?<!                 ) # Match iff there is no...
                 (x+x)  # integer >= 2...
         (?=\1*$)       # that divides the current number...
     ^\1*               # and also divides the input

5

J, 11 byte

+/@(1=+.)i.

uso

>> f =: +/@(1=+.)i.
>> f 44
<< 20

dove >>è STDIN ed <<è STDOUT.

Spiegazione

+/ @ ( 1 = +. ) i.
               │
   ┌───────────┴┐
 +/@(1=+.)      i.
   │
 ┌─┼──┐
+/ @ 1=+.
    ┌─┼─┐
    1 = +.

>> (i.) 44            NB. generate range
<< 0 1 2 3 4 ... 43
>> (+.i.) 44          NB. calculate gcd of each with input
<< 44 1 2 1 4 ... 1
>> ((1=+.)i.) 44      NB. then test if each is one (1 if yes, 0 if no)
<< 0 1 0 1 0 ... 1
>> (+/@(1=+.)i.) 44   NB. sum of all the tests
<< 20

Come hai ottenuto la rappresentazione ad albero verticale? Ho pensato che producesse solo orizzontale.
miglia

@miles l'ho scritto da solo.
Leaky Nun,

5

Python> = 3.5, 76 64 58 byte

Grazie a LeakyNun per aver giocato a golf fuori da 12 (!) Byte.

Grazie a Sp3000 per giocare a golf con 6 byte.

import math
lambda n:sum(math.gcd(n,x)<2for x in range(n))

Adoro quanto sia leggibile Python. Questo ha senso, anche attraverso il golf.


1
lambda n:sum(gcd(n,x)<2for x in range(n))
Leaky Nun,

Oh, Python finalmente aggiunto gcdal modulo di matematica! Non lo sapevo.
rubik,

4

Perl 6 ,  26 24  22 byte

{[+] (^$^n Xgcd $n) X== 1}
{+grep 2>*,(^$_ Xgcd$_)}
{[+] 2 X>(^$_ Xgcd$_)}

Spiegazione:

{
  [+] # reduce using &infix:<+>
    2
    X[>] # crossed compared using &infix:«>»
    (
      ^$_    # up to the input ( excludes input )
      X[gcd] # crossed using &infix:<gcd>
      $_     # the input
    )
}

Esempio:

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

my  = {[+] 2 X>(^$_ Xgcd$_)};

say φ(1) # 1
say φ(2) # 1
say φ(3) # 2
say φ(8) # 4
say φ(9) # 6
say φ(26) # 12
say φ(44) # 20
say φ(105) # 48

say φ 12345 # 6576


4

Julia, 25 byte

!n=sum(i->gcd(i,n)<2,1:n)

È semplice - la sumfunzione ti consente di dargli una funzione da applicare prima del riepilogo - fondamentalmente l'equivalente di corsa mape poi sum. Questo conta direttamente il numero di numeri relativamente primi primi di n.


4

Python 2, 57 byte

f=lambda n,k=1,m=1:n*(k>n)or f(n-(n%k<m%k)*n/k,k+1,m*k*k)

Provalo su Ideone .

sfondo

Dalla formula del prodotto di Eulero ,

Euler's product formula

dove φ indica la funzione di totaggio di Eulero e p varia solo rispetto ai numeri primi.

Per identificare i numeri primi, usiamo un corollario del teorema di Wilson :

corollary of Wilson's theorem

Come funziona

In ogni momento, la variabile m sarà uguale al quadrato del fattoriale di k - 1 . In effetti, abbiamo chiamato argomenti predefiniti su k = 1 e m = 0! 2 = 1 .

Finché k ≤ n , viene n*(k>n)valutato a 0 e il codice seguente orviene eseguito.

Ricordiamo che m%kprodurrà 1 se m è primo e 0 in caso contrario. Ciò significa che x%k<m%kprodurrà True se e solo se entrambi k è un numero primo e x è divisibile per k .

In questo caso, (n%k<m%k)*n/kproduce n / k e sottraendolo da n sostituisce il suo valore precedente con n (1 - 1 / k) , come nella formula del prodotto di Eulero. Altrimenti, i (n%k<m%k)*n/krendimenti 0 e n rimangono invariati.

Dopo aver calcolato quanto sopra, incrementiamo k e moltiplichiamo m per il "vecchio" valore di k 2 , mantenendo così la relazione desiderata tra k e m , quindi chiamiamo f in modo ricorsivo con gli argomenti aggiornati.

Una volta k supera n , n*(k>n)restituisce n , che viene restituita dalla funzione.


4

Rubino, 32 byte

->n{(1..n).count{|i|i.gcd(n)<2}}

un lambda che accetta un numero intero n e restituisce i conteggi di quanti numeri interi nell'intervallo (1..n) sono coprimi con n.


Ciao e benvenuto in PPCG! Questo è un ottimo primo post.
NoOneIsHere il

Benvenuti in Puzzle di programmazione e Code Golf! Questa è un'ottima prima soluzione, continuate così!
bkul,

Grazie, non molto breve, mi chiedo se sia possibile migliorarlo.
Redouane Red,

3

Brachylog , 25 byte

:{:1e.$pdL,?$pd:LcCdC}fl.

Spiegazione

Brachylog non ha ancora incorporato GCD, quindi controlliamo che i due numeri non abbiano in comune fattori primi.

  • Predicato principale:

    :{...}fl.             Find all variables which satisfy predicate 1 when given to it as
                          output and with Input as input.
                          Unify the Output with the length of the resulting list
    
  • Predicato 1:

    :1e.                  Unify Output with a number between Input and 1
        $pdL              L is the list of prime factors of Output with no duplicates
            ,
             ?$pd:LcC     C is the concatenation of the list of prime factors of Input with
                          no duplicates and of L
                     dC   C with duplicates removed is still C
    

3

Pyth, 6 byte

smq1iQ

Provalo online!

/iLQQ1

Provalo online!

Spiegazione

smq1iQ     input as Q
smq1iQdQ   implicitly fill variables

 m     Q   for d in [0 1 2 3 .. Q-1]:
    iQd        gcd of Q and d
  q1           equals 1? (1 if yes, 0 if no)
s          sum of the results


/iLQQ1     input as Q

 iLQQ      gcd of each in [0 1 2 3 .. Q-1] with Q
/    1     count the number of occurrences of 1

3

PowerShell v2 +, 72 byte

param($n)1..$n|%{$a=$_;$b=$n;while($b){$a,$b=$b,($a%$b)};$o+=!($a-1)};$o

PowerShell non ha una funzione GCD disponibile, quindi ho dovuto implementare la mia.

Questo riceve l'input $n, quindi va da 1a $ne tubi quelle in un ciclo |%{...}. Ogni iterazione abbiamo impostato due variabili di supporto $ae $bquindi eseguire un GCD whileciclo. Ogni iterazione che stiamo verificando $bè ancora diversa da zero, quindi salviamo $a%$bin $be il valore precedente di $bto $aper il ciclo successivo. Quindi accumuliamo se $aè uguale a 1nella nostra variabile di output $o. Una volta terminato il ciclo for, posizioniamo$o sulla pipeline e l'output è implicito.

Come esempio di come funziona il whileloop, considera $n=20e siamo su $_=8. Il primo controllo ha $b=20, quindi entriamo nel loop. Per prima cosa calcoliamo $a%$bo 8%20 = 8, che viene impostato $ballo stesso tempo su cui 20viene impostato $a. Verifica 8=0e inseriamo la seconda iterazione. Quindi calcoliamo 20%8 = 4e impostiamo questo su $b, quindi impostiamo $asu 8. Verifica 4=0e inseriamo la terza iterazione. Calcoliamo 8%4 = 0e impostiamo questo su $b, quindi impostiamo $asu 4. Controlla 0=0e usciamo dal loop, quindi GCD (8,20) lo è $a = 4. Quindi, !($a-1) = !(4-1) = !(3) = 0così $o += 0e non contiamo quello.


3

Fattore, 50 byte

[ dup iota swap '[ _ gcd nip 1 = ] filter length ]

Crea un intervallo ( iota ) n e inserisce n in una funzione che ottiene gcd xn per tutti i valori di 0 <= x <= n , verifica se il risultato è 1 . Filtra l'intervallo originale in base al fatto che il risultato di gcd xn fosse 1 e ne abbia la lunghezza .


[ dup iota swap '[ _ gcd nip 1 = ] map sum ]salva 6 byte (penso - non molto esperto con Factor).
bkul

@bkul Grazie per il suggerimento! : D Sfortunatamente, non esiste alcuna compatibilità tra numeri e t/f(simboli) in Factor, quindi l'unico modo per implementarlo sarebbe con [ dup iota swap '[ _ gcd nip 1 = 1 0 ? ] map sum ]la stessa lunghezza esatta della soluzione attuale.
gatto,

Ah, dang. La digitazione forte colpisce ancora.
bkul

@bkul Bene, sono grato per la digitazione forte e TYPED:nel vero codice fattore: P
cat


2

Retina, 36 29 byte

7 byte grazie a Martin Ender.

.+
$*
(?!(11+)\1*$(?<=^\1+)).

Provalo online!

Spiegazione

Esistono due fasi (comandi).

Primo stadio

.+
$*

È una semplice sostituzione regex, che converte l'input in tanti.

Ad esempio, 5verrebbe convertito in 11111.

Seconda fase

(?!(11+)\1*$(?<=^\1+)).

Questa regex cerca di abbinare le posizioni che soddisfano la condizione (co-prime con input), quindi restituisce il numero di corrispondenze.


Lookbehind non fa marcia indietro se non all'interno di un lookahead?
Leaky Nun,

I lookaround non fanno marcia indietro in generale.
Martin Ender,

Allora come mai il regex ha testato tutti i divisori?
Leaky Nun,

1
Beh, fanno marcia indietro finché non li lasci. Finché il motore è all'interno del lookaround, proverà tutto il possibile per far corrispondere quel lookaround (o fallire in caso di lookaround negativo). Ma una volta superato il lookaround, il motore non tornerà indietro in esso se qualcosa dopo non riesce (a meno che non inizi anche a tornare indietro alle cose di fronte al lookaround e deve comunque rivalutare tutto).
Martin Ender,


2

Lisp comune, 58 byte

(defun o(x)(loop for i from 1 to x if (=(gcd x i)1)sum 1))

Questo è un semplice ciclo che conta fino a 1 dato n e incrementa la somma se gcd = 1. Uso il nome della funzione o poiché t è il vero valore booleano. Non quasi il più breve ma abbastanza semplice.


CL non ha una sorta di funzione anonima?
cat

2

MATLAB / Octave, 21 byte

@(n)sum(gcd(n,1:n)<2)

Crea una funzione anonima denominata ansche può essere chiamata con l'intero ncome unico input:ans(n)

Demo online




2

C (gcc) , 67 65 byte

f(x,a,b,y,z){for(z=y=x;a=y--;z-=b>1)for(b=x;a^=b^=a^=b%=a;);x=z;}

Provalo online!

Modifica: variabile temporanea rimossa.

Edit2: -1 grazie a @HowChen

Leggermente meno golfato

f(x,a,b,y,z){
  // counts y NOT coprime with x and subtract
  for(z=y=x;a=y--;z-=b>1)
    // compute GCD
    for(b=x;a^=b^=a^=b%=a;);
  x=z;
}

1

In realtà, 11 byte

;╗R`╜g`M1@c

Provalo online!

Spiegazione

;╗R`╜g`M1@c   register stack             remarks

                       44
;                      44 44
 ╗            44       44
  R           44       [1 2 3 .. 44]
       M      44       10                for example
    ╜         44       10 44
     g        44       2
              44       [1 2 1 .. 44]     gcd of each with register
        1     44       [1 2 1 .. 44] 1
         @    44       1 [1 2 1 .. 44]
          c   44       20                count

Con incorporato

Provalo online!


In alternativa, puoi utilizzare ;╗R`╜g1=`MΣlo stesso numero di byte
Mego

1

JavaScript (ES6), 67 byte

f=n=>[...Array(n)].reduce(r=>r+=g(n,++i)<2,i=0,g=(a,b)=>b?g(b,a%b):a)

1

APL, 7 byte

+/1=⊢∨⍳

Questo è un treno di funzioni monadico che accetta un numero intero sulla destra. L'approccio qui è ovvio: sum ( +/) il numero di volte in cui il GCD dell'ingresso e i numeri da 1 a input ( ⊢∨⍳) è uguale a 1 ( 1=).

Provalo qui


1

Haskell, 31 30 byte

\n->sum[1|x<-[1..n],gcd n x<2]

1 byte salvato, grazie a @Damien.

Seleziona i valori con gcd = 1, mappa ciascuno su 1, quindi prende la somma.


Puoi sostituirlo ==1con<2
Damien il
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.