求N的除数之和


20

编写一个程序,在屏幕上显示用户输入的1到N范围内的数字(1≤N≤100)的除数之和。

这是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的除数”

我认为您是指除数之和,即sigma函数
斯蒂芬

抱歉,我的意思是“ N的倍数之和”。
凯文·哈雷

@ H.PWiz这是这些的总和,所以我不知道
Stephen

@Stephen对我来说似乎是微不足道的更改
H.PWiz

Answers:



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)指令来执行模运算,而这两个都使用固定的输入寄存器(EDXEAX),它们的值被破坏了(因为它们接收到结果,其余的和商)。

这里唯一真正的技巧是相当标准的高尔夫技巧:

  • 我以某种不寻常的方式构造了代码,以便可以使用CISC样式的LOOP指令,该指令基本上只是DEC+ JNZ与组合ECX作为隐式操作数的组合。
  • XCHG在末尾使用,而不是MOV因为当EAX操作数之一时,前者具有特殊的1字节编码。
  • 我通常CDQ将零归零EDX以准备除法,即使对于无符号除法,通常您会使用a将其归零XOR。但是,XOR始终为2个字节,而CDQ仅为1个字节。我在指令之前CDQ再次在循环内第二次使用零。之所以可行,是因为可以确保除法(in )中的商始终是无符号的,因此将符号扩展到的值将设置为0。EDXCMOVZEAXEDXEDX




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
@Loki 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中,整数隐式转换为布尔值(零=> false,而不是零=> true),因此您不需要 !=0

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

D优化:golfy模板系统,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));

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

一些注意事项:首先,我认为您不需要在任何一种语言中的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先生(大声笑了,我用我自己的语言感到厌烦)

 $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
==0<143个字节
Xcoder先生17年

@先生。Xcoder谢谢。。。我感到厌烦了。。。用我自己的语言。。。这甚至都不是深奥的xD
Socratic Phoenix,

2

Python,44个字节

lambda k:sum(i*(k%i<1)for i in range(1,1+k))
  • 感谢Stephen,通过删除空格节省了1个字节。
  • 多亏了乔纳森·弗雷希(Jonathan Frech),通过更改是否乘以来节省另外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.|]
英里

@miles,真的很好。这部分是i.|]对我的方法的极大改进。不过,我还没有完全理解这一部分:+1#.i.-您能解释一下吗?
约拿(Jonah)

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)

感谢Shaggy,节省了10个字节

在线尝试!

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

那是对mod的修改,M如果它是N0其他因素,将会给我们。完整代码如下。

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

R31 26字节

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

在线尝试!

返回一个1x1矩阵。

单位计算!N%%x映射元素d1:N方式:d->(1 if d divides N, 0 otherwise)

然后x%*%x!N%%x是矩阵乘积1:N中的总和,其结果x,其中!N%%x1。整齐!从技术上讲,是路易斯·门多(Luis Mendo)的八度音阶的答案,但我想到此后才看到。

R +数字,14个字节

numbers::Sigma

在线尝试!


对于第一个,您可以使用N=scan();
gstats

@gstats是的,但是每个meta讨论我应该获得+4个字节。如果您有强烈的意见,可以考虑Jarko的回答,但是由于没有人建议替代方案,因此我认为这是可行的。
朱塞佩

第二个不应该numbers::Sigma(N)吗?这样,它输出函数的源代码Sigma
Rui Barradas

@RuiBarradas函数是一个非常好的提交。要测试它,您显然必须像我在第一次提交中一样调用它。
朱塞佩

1

JavaScript,31个字节

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



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 Y... 转换为子例程End Sub以获得85字节的解决方案Sub 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

然而,可以将其优化到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

除此之外,并认识到您的解决方案不通过子程序调用取输入,这然后可以被转换为50个字节的VBE即时窗口函数While x<=[A1]:x=x+1:b=IIf([A1]Mod x,b,b+x):Wend:?b,其假定xb是默认值0,并输出到VBE即时窗口(从(VBE即时视窗?等于Debug.Print
Taylor Scott

1

Pyth,6个字节

s*M{yP

在这里尝试!

Pyth没有除数的内置函数,因此我认为这是合理的。

说明

s * M {yP-带有隐式输入的完整程序。

     P-输入的素数。
    y-其主要因子的幂集。
   {-重复数据删除。
 * M-乘法映射。
s-总和。
          -隐式显示结果。

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]

  • s42



1

外壳,5个字节

ṁΠuṖp

在线尝试!

怎么样?

-ΠuṖp-完整程序,隐式输入。

     p-素因子。
    Ṗ-Powerset。
   u-删除重复项。
-Π-获取每个列表,总和和隐式输出的乘积。

感谢Zgarb的聊天建议!





0

Bash + GNU实用程序,36

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

在线尝试


纯净重击,41

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

在线尝试

我首先尝试了一个花哨的bash扩展答案,但最终比上面的简单循环更长:

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


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.