Trova la somma dei divisori di N


20

Scrivi un programma che visualizza sullo schermo la somma dei divisori di un numero (1 ≤ N ≤ 100) inserito dall'utente nell'intervallo da 1 a N.

Questo è OEIS A000203 .


Esempi:

Ingresso : 7

7 / 1 = 7
7 / 7 = 1

7 + 1 = 8

Uscita: 8


Ingresso: 15

15 / 1 = 15
15 / 3 = 5
15 / 5 = 3
15 / 15 = 1

15 + 5 + 3 + 1 = 24

Uscita: 24


Ingresso: 20

20 / 1 = 20
20 / 2 = 10
20 / 4 = 5
20 / 5 = 4
20 / 10 = 2
20 / 20 = 1

20 + 10 + 5 + 4 + 2 + 1 = 42

Uscita: 42


Ingresso: 1

1 / 1 = 1

Uscita: 1


Ingresso: 5

5 / 1 = 5
5 / 5 = 1

5 + 1 = 6

Uscita: 6


6
@ H.PWiz Penso che significhi "i divisori di un numero N"
benzene

Penso che intendi la somma dei divisori, ovvero la funzione sigma ?
Stephen,

Scusa, intendo "La somma del multiplo di N".
Kevin Halley,

@ H.P.Wiz questa è la somma di quelle, quindi non lo so
Stephen

@Stephen Questo mi sembra un banale cambiamento
H.PWiz

Risposte:



6

x86-64 Codice macchina, 23 byte

89 F9 89 FE EB 0D 89 F8 99 F7 F1 85 D2 99 0F 44 D1 01 D6 E2 F1 96 C3

I byte di codice sopra definiti definiscono una funzione che accetta un singolo intero, N, e di conseguenza restituisce la somma dei suoi multipli.

Il singolo parametro viene passato nel EDIregistro, coerentemente con l'ABI System V AMD64 (utilizzato sui sistemi in stile * nix). Il risultato viene restituito nel EAXregistro, come per tutte le convenzioni di chiamata x86.

L'algoritmo è molto semplice, simile a molti altri argomenti in altre lingue. Facciamo un ciclo N di volte, calcolando ogni volta il modulo e aggiungendolo al nostro totale corrente.

Mnemonici di assemblaggio non golfati:

; unsigned SumOfMultiples(unsigned N  /* (EDI) */)
    mov     ecx, edi      ; make copy of input N, to be used as our loop counter
    mov     esi, edi      ; make copy of input N, to be used as our accumulator
    jmp     CheckEnd      ; jump directly to 'CheckEnd'
AddModulo:
    mov     eax, edi      ; make copy of input N, to be used as input to DIV instruction
    cdq                   ; short way of setting EDX to 0, based on EAX
    div     ecx           ; divide EDX:EAX by ECX, placing remainder in EDX
    test    edx, edx      ; test remainder, and set ZF if it is zero
    cdq                   ; again, set EDX to 0, without clobbering flags
    cmovz   edx, ecx      ; set EDX to ECX only if remainder was zero (EDX = ZF ? 0 : ECX)
    add     esi, edx      ; add EDX to accumulator
CheckEnd:
    loop    AddModulo     ; decrement loop counter (ECX), and keep looping if it != 0
    xchg    eax, esi      ; move result from accumulator (ESI) into EAX
    ret                   ; return, with result in EAX

Provalo online!

Sembra che ci dovrebbe essere un modo per accorciarlo, ma non riesco a vederlo. Il calcolo del modulo su x86 richiede un bel po 'di codice, dal momento che lo fai usando l' istruzione DIV(o IDIV), ed entrambi usano registri di input fissi ( EDXe EAX), i cui valori vengono bloccati (perché ricevono i risultati, il resto e quoziente, rispettivamente).

Gli unici veri trucchi qui sono quelli da golf piuttosto standard:

  • Ho strutturato il codice in un modo un po 'insolito in modo da poter usare l'istruzione in stile CISC LOOP, che è fondamentalmente solo una combinazione di DEC+ JNZcon il ECXregistro come operando implicito.
  • Sto usando XCHGalla fine invece che MOVperché il primo ha una speciale codifica a 1 byte quando EAXè uno degli operandi.
  • Uso CDQper azzerare EDXin preparazione per la divisione, anche se per la divisione senza segno normalmente si azzererebbe semplicemente usando a XOR. Tuttavia, XORè sempre 2 byte, mentre CDQè solo 1 byte. Uso di CDQnuovo una seconda volta all'interno del loop a zero EDX, prima CMOVZdell'istruzione. Questo funziona perché posso essere sicuro che il quoziente della divisione (in EAX) sia sempre senza segno, quindi un'estensione del segno in EDXsarà impostata EDXsu 0.




3

Mathematica, 14 byte

Tr@Divisors@#&   

o una risposta di @Loki

Mathematica, 17 byte

DivisorSum[#,#&]&

@Jennymathy Molto bella, grazie! Un modo equivalente e divertente per scriverlo è anche: DivisorSum [#, # &] &
Rebel-Scum

@Jennymathy Hmm, questo è ancora meglio: Total @ Divisors @ è lungo solo 15 caratteri! E funziona: ad es. Total @ Divisors @ 15 dà 24 come previsto. Mathematica FTW :)
Rebel-Scum

2
@Loki e Tr@Divisors@#&anche meglio ;-)
J42161217

1
@Loki il programma deve essere una funzione f=che accetta un input f [x] ecco perché lo presento in questo modo. Benvenuto in PPCG
J42161217

3
Puoi usare Tr@*Divisorsper radere un byte.
wchargin,

3

C, C ++, C #, D, Java, 65 62 byte

int d(int n){int s=0,i=1;for(;i<=n;++i)s+=n%i>0?0:i;return s;}

Funziona in tutti questi 5 linguaggi di programmazione a causa di somiglianze.

Ottimizzazione C, C ++ e D: 62 60 byte

In C ++ e D, gli interi vengono convertiti implicitamente in booleani (Zero => false, Not Zero => true), quindi non è necessario avere il !=0

int d(int n){int s=0,i=1;for(;i<=n;++i)s+=n%i?0:i;return s;}

Ottimizzazione D: sistema di template golfy, 55 byte

T d(T)(T n){T s,i=1;for(;i<=n;++i)s+=n%i?0:i;return s;}

Codice da testare :

C:

printf("%d %d %d %d %d", d(7), d(15), d(20), d(1), d(5));

C ++:

std::cout << d(7) << ' ' << d(15) << ' ' << d(20) << ' ' << d(1) << ' ' << d(5);

C #:

class FindSum
{
    int d(int n) { int s = 0, i = 1; for (; i <= n; ++i) s += n % i > 0 ? 0 : i; return s; }

    static void Main(string[] args)
    {
        var f = new FindSum();
        Console.WriteLine(string.Format("{0}, {1}, {2}, {3}, {4}", f.d(7), f.d(15), f.d(20), f.d(1), f.d(5)));
    }
}

D:

writeln(d(7));
writeln(d(15));
writeln(d(20));
writeln(d(1));
writeln(d(5));

Java:

public class FindSum {
    int d(int n){int s=0,i=1;for(;i<=n;++i)s+=n%i>0?0:i;return s;}

    public static void main(String[] args) {
        FindSum f = new FindSum();
        System.out.println(String.format("%d, %d, %d, %d, %d", f.d(7), f.d(15), f.d(20), f.d(1), f.d(5)));
    }
}

Alcune cose: in primo luogo, non credo che occorrano parentesi in n%i/ n%i!=0in nessuna delle lingue. Secondo, la tua prima soluzione dovrebbe essere in grado di avere n%i>0invece di n%i!=0. Terzo, la soluzione di D può essere T d(T)(T n){T s,i=1;for(;i<=n;++i)s+=n%i?0:i;return s;}abusando del sistema modello e dei valori predefiniti.
Zacharý,

3

Shnap , 44 43 byte

-1 ciao grazie a Mr. Xcoder (lol ero superato nella mia lingua)

 $n return:{s=0for d:range(n+1)if n%d<1s+=d}

Questa è una funzione ( $avvia una funzione in Shnap).

Provalo online!

Spiegazione:

$ n                        //Start function with parameter n
    return: {              //Technically, we are returning a scope-block, which evaluates to the last statement run
        s = 0              //Our result
        for d : range(n+1) //For each value in the iterator range(n+1)
            if n % d < 1  // If n is divisible by d
                s += d     // Add d to the sum
                           // Since (s += d) returns (s + d), and a scope-block returns the last run statement, this will be the last statement and equal to our result
    }

Non competitivo, 19 byte

Dopo molti aggiornamenti di lingua, questo può ora essere ridotto a misero 19 byte:

$n=>sum(factors(n))

Provalo online!


1
==0è <1( 43 byte )
Mr. Xcoder l'

@Sig. Xcoder grazie ... Ero troppo superato ... Nella mia lingua ... Che non è nemmeno esoterico xD
Socratic Phoenix

2

Python, 44 byte

lambda k:sum(i*(k%i<1)for i in range(1,1+k))
  • Grazie a Stephen, risparmia 1 byte rimuovendo gli spazi bianchi.
  • Grazie a Jonathan Frech, salva un altro 1 byte cambiando se moltiplicare.

2

J, 23 byte

[:+/](([:=&0]|[)#])1+i.

Provalo online!

Per i fan di J, esiste una soluzione intelligente a 13 byte : >:@#.~/.~&.q:ma poiché non è stata una mia invenzione, non la sto pubblicando come risposta ufficiale.

La mia soluzione semplicemente filtra 1..n, trova i divisori, quindi li somma. Il punto cruciale è la forcella diadica

](([:=&0]|[)#])

Si noti che in questo contesto ]è 1..n ed [è n stesso. Quindi ]|[sono i resti quando si divide ogni elemento di 1..n in n, e =&0ti dice se sono uguali a 0.


2
Questo per 13 byte dovrebbe essere equivalente:+1#.i.*0=i.|]
miglia

@miles, è davvero bello. Questa parte è i.|]un grande miglioramento nel mio approccio. Non capisco perfettamente questa parte però: +1#.i.- potresti spiegarlo?
Giona,

2
1#.è la conversione di base 1, che equivale a +/"1. Prima i.|]di ottenere i resti, poi 0=di trovare quelli uguali a 0 (i divisori), quindi i.*di azzerare i non divisori nell'intervallo, quindi sommare usando 1#., quindi aggiungersi +poiché i.è un intervallo esclusivo.
miglia




2

Javascript, 54 44 byte

n=>[...Array(x=n)].reduce(y=>y+!(n%x)*x--,0)

Risparmiato 10 byte grazie a Shaggy

Provalo online!

const f = n=>[...Array(x=n)].reduce(y=>y+!(n%x)*x--,0)

console.log(f(7))
console.log(f(15))
console.log(f(20))
console.log(f(1))
console.log(f(5))


2

Brain-Flak , 96 byte

((({})<>){<(([()]{})){<>(({})(<()>))<>{(({})){({}[()])<>}{}}{}<>([{}()]({})){((<{}{}>))}}{}>{}})

Provalo online!

Spiegazione:

Ora obsoleto da miglioramenti.

Il cuore dell'algoritmo è questo:

({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]({})) turns |N, M...| into |N mod M, M...|
{((<{}{}>))} if the top of stack is not zero, replace it and the second with zero

Questa è una modifica alla mod che ci darà Mse è un fattore di Ne 0altrimenti. Il codice completo è sotto.

((({})<>) place input, N on both stacks
{ Loop to find factors
 <
  (([()]{})) Decrement and Duplicate; get next factor to check
  { if not zero
   (<>({})<>) Copy N from other stack
   ({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]({})){((<{}{}>))} Code explained above
  }
  {} drop the zero
 >
 {} add the factor
}) push the sum

Hai una spiegazione?
Mago del grano,

@FunkyComputerMan Ne ho preso uno adesso!
MegaTom,

2

R , 31 26 byte

function(N)(x=1:N)%*%!N%%x

Provalo online!

Restituisce a 1x1 matrice.

Calcola gli !N%%xelementi ddelle mappe di1:N :d->(1 if d divides N, 0 otherwise)

Quindi x%*%x!N%%xè il prodotto matrice di 1:Ncui risulta la somma di xdove si !N%%xtrova 1. ! Neat Tecnicamente un porto della risposta Octave di Luis Mendo ma l'ho visto solo dopo averci pensato.

R + numeri, 14 byte

numbers::Sigma

Provalo online!


Per il primo è possibile salvare 2 byte conN=scan();
gstats

@gstats sì, ma allora dovrei ottenere +4 byte per meta discussione . Se hai una forte opinione, puoi ponderare sulla risposta di Jarko, ma poiché nessuno ha suggerito un'alternativa, questo mi viene in mente.
Giuseppe,

Il secondo non dovrebbe essere numbers::Sigma(N)? In questo modo genera il codice sorgente della funzione Sigma.
Rui Barradas - Ripristina Monic l'

@RuiBarradas una funzione è una presentazione perfettamente buona. per provarlo, ovviamente devi chiamarlo come faccio nella prima presentazione.
Giuseppe,

1

JavaScript, 31 byte

f=(n,i=n)=>i&&!(n%i)*i+f(n,i-1)



1

VBA (Excel), 73 byte

a=Cells(1,1)
x=1
While x<=a
If a Mod x = 0 Then b=b+x
x=x+1
Wend
MsgBox b

Questa risposta non è valida in quanto è una raccolta di frammenti che non possono essere eseguiti come una singola unità. Per renderlo valido dovrai convertirlo in una subroutine o in una funzione finestra immediata VBE anonima.
Taylor Scott,

Non ho molta familiarità con quello che hai detto. Potete aiutarmi un po 'di più?
Ritocca il

Per rendere valido questo post dovresti convertirlo in uno dei seguenti formati, 1 - Sottoprogramma, 2 - Funzione, 3 - Funzione finestra immediata VBE anonima (una singola riga che può essere eseguita nella finestra immediata); Per la tua implementazione, la più semplice implementazione di questo sarebbe convertire in un sottoprogramma avvolgendo con Sub Y... End Subper ottenere la soluzione 85 ByteSub y A=Cells(1,1) x=1 While x<=A If A Mod x=0 Then b=b+x x=x+1 Wend MsgBox b End Sub
Taylor Scott

Che tuttavia può essere ottimizzato abbastanza pesantemente fino alla soluzione a 72 byte Sub y While x<=[A1] x=x+1 If [A1]Mod x=0Then b=b+x Wend Debug.?b End Subche presuppone che venga eseguito in un modulo pulito (x = valore int predefinito, 0) e trasmesso alla finestra immediata VBE ( ?formattazione automatica per Print )
Taylor Scott

Oltre a ciò, e riconoscendo che la tua soluzione non While x<=[A1]:x=x+1:b=IIf([A1]Mod x,b,b+x):Wend:?baccetta input tramite la chiamata di subroutine, questa può essere convertita in una funzione di finestra immediata VBE per 50 byte che presuppone che x, bsiano il valore predefinito di 0 e restituisca alla finestra immediata VBE (da la finestra immediata di VBE ?equivale a Debug.Print )
Taylor Scott

1

Pyth , 6 byte

s*M{yP

Provalo qui!

Pyth non ha un built-in per i divisori, quindi penso che questo sia ragionevole.

Spiegazione

s * M {yP - Programma completo con input implicito.

     P - I fattori primi dell'input.
    y - Il powerset dei suoi fattori primi.
   {- Deduplicato.
 * M - Mappa con moltiplicazione.
s - Somma.
          - Visualizza implicitamente il risultato.

Dato 20, ad esempio, questo è ciò che fa il nostro programma dopo ogni istruzione:

  • P: [2, 2, 5].

  • y: [[], [2], [2], [5], [2, 2], [2, 5], [2, 5], [2, 2, 5]].

  • {: [[], [2], [5], [2, 2], [2, 5], [2, 2, 5]].

  • *M: [1, 2, 5, 4, 10, 20].

  • s: 42.



1

Buccia , 5 byte

ṁΠuṖp

Provalo online!

Come?

ṁΠuṖp - Programma completo, input implicito.

     p - Fattori primi.
    Ṗ - Powerset.
   u - Rimuovere i duplicati.
ṁΠ: ottieni il prodotto di ogni elenco, somma e output implicito.

Grazie a Zgarb per i suggerimenti in chat!





0

Utilità Bash + GNU, 36

bc<<<`seq -f"n=%g;a+=n*!$1%%n;" $1`a

Provalo online .


Pure Bash, 41

for((;++i<=$1;a+=$1%i?0:i))
{
:
}
echo $a

Provalo online .

Per prima cosa ho provato una risposta di espansione bash fantasia, ma alla fine è stato più lungo del semplice ciclo sopra:

echo $[$(eval echo +\\\(n={1..$1},$1%n?0:n\\\))]


0

QBIC , 17 byte

[:|~b%a|\p=p+a}?p

Spiegazione

[:|      FOR a = 1; a <= b (read from cmd line); a++
~b%a|    IF b modulo a has a remainder THEN - empty block - 
\p=p+a   ELSE add divisor 'a' to running total 'p'
}        END IF, NEXT
?p       PRINT p

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.