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.