Найти сумму делителей N


20

Напишите программу, которая отображает на экране сумму делителей числа (1 ≤ N ≤ 100), введенных пользователем в диапазоне от 1 до N.

Это OEIS A000203 .


Примеры:

Вход : 7

7 / 1 = 7
7 / 7 = 1

7 + 1 = 8

Выход: 8


Вход: 15

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

15 + 5 + 3 + 1 = 24

Выход: 24


Вход: 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

Выход: 42


Вход: 1

1 / 1 = 1

Выход: 1


Вход: 5

5 / 1 = 5
5 / 5 = 1

5 + 1 = 6

Выход: 6


6
@ H.PWiz Я думаю, что он имеет в виду «делители числа N»
бензол

Я думаю, что вы имеете в виду сумму делителей, иначе, сигма-функцию ?
Стивен

Извините, я имею в виду «сумма, кратная N».
Кевин Галлей,

@ H.PWiz это сумма тех, так что я не знаю
Стивен

@Stephen Это кажется мне тривиальным изменением
H.PWiz

Ответы:



6

Машинный код x86-64, 23 байта

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

Приведенные выше байты кода определяют функцию, которая принимает одно целое число N и в результате возвращает сумму его кратных.

Одиночный параметр передается в EDIрегистр, в соответствии с System V AMD64 ABI (как используется в системах * nix-стиля). Результат возвращается в EAXрегистр, как и во всех соглашениях о вызовах x86.

Алгоритм очень прост, похож на многие другие материалы на других языках. Мы зациклились N раз, каждый раз вычисляя по модулю и добавляя это к нашему текущему итогу.

Неуправляемая сборка мнемоники:

; 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

Попробуйте онлайн!

Кажется, кажется, должен быть способ сделать это короче, но я не вижу этого. Вычисление по модулю на x86 занимает довольно много кода, так как вы делаете это с помощью инструкции DIV(или IDIV), и оба из них используют фиксированные входные регистры ( EDXи EAX), значения которых засоряются (потому что они получают результаты, остаток и частное соответственно).

Единственные настоящие трюки здесь довольно стандартные:

  • Я структурировал код несколько необычным образом, так что я могу использовать LOOPинструкцию в стиле CISC , которая в основном является просто комбинацией DEC+ JNZс ECXрегистром в качестве неявного операнда.
  • Я использую XCHGв конце вместо того, MOVпотому что у первого есть специальная 1-байтовая кодировка, когда EAXодин из операндов.
  • Я использую, CDQчтобы обнулить EDXпри подготовке к разделению, даже если для беззнакового разделения вы обычно просто обнуляете его, используя a XOR. Тем не менее, XORвсегда 2 байта, а CDQтолько 1 байт. Я CDQснова использую второй раз внутри цикла до нуля EDX, перед CMOVZинструкцией. Это работает, потому что я могу гарантировать, что частное от деления (в EAX) всегда без знака, поэтому расширение знака в EDXустановитEDX равным 0.




3

Mathematica, 14 байтов

Tr@Divisors@#&   

или ответ @Loki

Mathematica, 17 байт

DivisorSum[#,#&]&

@ Jennymathy Очень хорошо, спасибо! Эквивалентный и забавный способ написать это также: DivisorSum [#, # &] &
Rebel-Scum

@ Jennymathy Хм, это даже лучше: Total @ Divisors @ всего 15 символов! И это работает: например, Total @ Divisors @ 15 дает 24, как и ожидалось. Mathematica FTW :)
Rebel-Scum

2
@ Локи и Tr@Divisors@#&даже лучше ;-)
J42161217

1
@Loki программа должна быть функцией, f=которая принимает ввод f [x], поэтому я представляю ее таким образом. Добро пожаловать в PPCG
J42161217

3
Вы можете использовать, Tr@*Divisorsчтобы сбрить байт.
wchargin

3

C, C ++, C #, D, Java, 65 62 байта

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

Это работает во всех тезисах 5 языков программирования из-за сходства.

C, C ++ и D оптимизация: 62 60 байтов

В C ++ и D целые числа неявно преобразуются в логические значения (Zero => false, Not Zero => true), поэтому вам не нужно иметь !=0

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

D оптимизация: система шаблонов для гольфа, 55 байтов

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

Код для тестирования :

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));

Джава :

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)));
    }
}

Несколько вещей: во-первых, я не думаю, что вам нужны круглые скобки вокруг n%i/ n%i!=0на любом из языков. Во-вторых, ваше первое решение должно быть в состоянии иметь n%i>0вместо n%i!=0. В-третьих, решение D может заключаться T d(T)(T n){T s,i=1;for(;i<=n;++i)s+=n%i?0:i;return s;}в злоупотреблении системой шаблонов и значениями по умолчанию.
Захари

3

Шнап , 44 43 байта

-1 до свидания благодаря мистеру Xcoder (LOL я был превзойден в отставке на моем родном языке)

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

Это функция ($ запускает функцию в Shnap).

Попробуйте онлайн!

Объяснение:

$ 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
    }

Неконкурентный, 19 байт

После многих языковых обновлений это теперь может быть уменьшено до жалких 19 байтов:

$n=>sum(factors(n))

Попробуйте онлайн!


1
==0is <1( 43 байта )
г-н Xcoder

@Г-н. Xcoder спасибо ... Я был вне поля зрения ... На моем родном языке ... Что даже не эзотерично xD
Сократический Феникс

2

Python, 44 байта

lambda k:sum(i*(k%i<1)for i in range(1,1+k))
  • Благодаря Стивену, сохраните 1 байт, удалив пробелы.
  • Благодаря Джонатану Фречу, сохраните еще 1 байт, изменив умножение.

2

J, 23 байта

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

Попробуйте онлайн!

Для поклонников J есть умное 13-байтовое решение : >:@#.~/.~&.q:но так как это было не мое изобретение, я не публикую его в качестве официального ответа.

Мое собственное решение просто фильтрует 1..n, находит делители, а затем суммирует их. Суть этого - диадическая вилка

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

Обратите внимание, что в этом контексте ]это 1..n, и [само n. Следовательно ]|[, остатки при делении каждого элемента из 1..n на n, и =&0говорит вам, если они равны 0.


2
Это для 13 байтов должно быть эквивалентно:+1#.i.*0=i.|]
миль

@ Майлз, это действительно мило. Эта часть является i.|]большим улучшением моего подхода. Я не до конца понимаю эту часть: +1#.i.- не могли бы вы объяснить это?
Иона

2
1#.конверсия базы 1, что эквивалентно +/"1. Сначала, i.|]чтобы получить остатки, затем 0=найти те, которые равны 0 (делители), затем i.*обнулить неразделители в диапазоне, затем суммировать 1#., затем добавить +себя, так i.как это исключительный диапазон.
миль




2

Javascript, 54 44 байта

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

Сохранено 10 байтов благодаря Shaggy

Попробуйте онлайн!

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 байт

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

Попробуйте онлайн!

Объяснение:

Сейчас устарели улучшения.

Суть алгоритма заключается в следующем:

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

Это модификация мода, которая даст нам, Mесли это фактор Nи 0иначе. Полный код ниже.

((({})<>) 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

У вас есть объяснение?
Пшеничный волшебник

@ FunkyComputerMan Я получил один сейчас!
MegaTom

2

R , 31 26 байт

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

Попробуйте онлайн!

Возвращает 1x1матрицу.

Вычисляет !N%%xкарты элементов dиз 1:Nпо:d->(1 if d divides N, 0 otherwise)

Тогда x%*%x!N%%xматричное произведение 1:Nкоторого приводит к сумме xгде !N%%xесть 1. Ухоженная! Технически порт Луиса Мендо в октавском ответе но я увидел это только после того, как подумал об этом.

R + числа, 14 байтов

numbers::Sigma

Попробуйте онлайн!


Для первого вы можете сохранить 2 байта с N=scan();
gstats

@gstats да, но тогда я должен получить +4 байта за мета-обсуждение . Если у вас есть твердое мнение, вы можете взвесить ответ Ярко, но, поскольку никто не предложил альтернативу, это стоит у меня на уме.
Джузеппе

Не должно быть второе numbers::Sigma(N)? Таким образом, он выводит исходный код функции Sigma.
Руи Баррадас - Восстановить Моник

@RuiBarradas функция является очень хорошим представлением. чтобы проверить это, вы, очевидно, должны назвать это, как я делаю в первом представлении.
Джузеппе




1

VBA (Excel), 73 байта

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

Этот ответ недопустим, так как представляет собой набор фрагментов, которые не могут быть выполнены как единое целое как стоящие. Чтобы сделать это действительным, вам нужно преобразовать это в подпрограмму или анонимную функцию непосредственного окна VBE.
Тейлор Скотт

Я не очень знаком с тем, что вы сказали. Можете ли вы помочь мне немного больше?
перемотать

Чтобы сделать этот пост действительным, вам нужно будет преобразовать его в один из следующих форматов: 1 - подпрограмма, 2 - функция, 3 - функция анонимного непосредственного окна VBE (единственная строка, которая может быть выполнена в окне немедленного действия); Для вашей реализации самой простой реализацией этого было бы преобразование в подпрограмму, Sub YEnd SubSub 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
Тейлор Скотт,

Это, однако, может быть довольно сильно оптимизировано вплоть до решения 72 байта Sub y While x<=[A1] x=x+1 If [A1]Mod x=0Then b=b+x Wend Debug.?b End Sub которое предполагает, что оно запускается в чистом модуле (x = значение по умолчанию int 0) и ?выводится в непосредственное окно VBE ( автоформаты в Print )
Taylor Scott

Помимо этого, и признавая , что ваше решение не принимает ввод с помощью вызова подпрограммы, это может быть преобразовано в VBE непосредственной функцию окна для 50 байт , While x<=[A1]:x=x+1:b=IIf([A1]Mod x,b,b+x):Wend:?bкоторый предполагает , что x, bявляется значение по умолчанию 0 и выводит в ближайшее окно VBE (от непосредственное окно VBE ?эквивалентно Debug.Print )
Тейлор Скотт

1

Pyth , 6 байт

s*M{yP

Попробуй это здесь!

В Pyth нет встроенных делителей, поэтому я думаю, что это разумно.

объяснение

s * M {yP - Полная программа с неявным вводом.

     P - основные факторы входа.
    у - powerset его основных факторов.
   {- Дубликат.
 * M - Карта с умножением.
с - сумма.
          - Неявно отображать результат.

Учитывая 20, например, это то, что наша программа делает после каждой инструкции:

  • 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

Шелуха , 5 байт

ṁΠuṖp

Попробуйте онлайн!

Как?

ṁΠuṖp - Полная программа, неявный ввод.

     п - основные факторы.
    Power - Powerset.
   u - Удалить дубликаты.
Get - Получить произведение каждого списка, суммировать и неявно выводить.

Спасибо Zgarb за предложения в чате!







0

QBIC , 17 байт

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

объяснение

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.