我正在尝试实现n * (n + 1) / 2
知道n
是int
&lt; = 2 ^ 16 - 1(这可以保证n * (n + 1) / 2 <= 2^31 - 1
所以没有溢出) 。
然后我们知道n * (n + 1) / 2
保证是非负整数。但是,当在程序中计算此值时,如果我们先进行乘法n *(n + 1)
,我们可能会遇到整数溢出问题。我的想法是使用笨拙的条件:
int m;
if (n % 2 == 0) {
m = (n / 2) * (n + 1);
} else {
m = n * ((n + 1) / 2);
}
还有更简洁的方法吗?
答案 0 :(得分:4)
使用三元运算符编写测试有一种更简洁的方法:
int m = (n % 2 == 0) ? (n / 2) * (n + 1) : n * ((n + 1) / 2);
但它可能会生成完全相同的代码。
您可以利用额外的精度long long
保证提供(至少63个值位):
int m = (long long)n * (n + 1) / 2;
这是否比测试版本效率更高或更低取决于目标CPU和编译器版本和选项。这个版本更易于阅读和理解,这很有价值。添加注释来解释结果将在范围内的原因将非常有用。
根据Amadeus的建议,这里有一个更简洁,但更不易读的替代方案,它不使用64位算术:
int m = (n + (n & 1)) / 2 * (n + 1 - (n & 1));
演示:
n
是奇数,我们会得到m = (n + 1) / 2 * n;
n
是偶数,我们会得到:m = n / 2 * (n + 1);
。答案 1 :(得分:3)
您如何看待:
m = ((n + (n & 1)) >> 1) * ( n + !(n & 1));
说明:
此解决方案尝试实现两个目标:
if then else
条件,并且管道友好为了避免溢出,我们首先划分和乘法。一旦除数达到一半(2),它就有一个有趣的属性:如果数字是奇数,则除法是精确的,可以通过简单的右筛选来完成。
因此,为了保证数字为奇数而没有if then else
条件,我们使用以下技巧:
如果number为奇数,则表示低位为零(通过1和1捕获),否则为偶数。因此,如果数字是奇数,我们将它除以2,否则,我们首先加1,以确保它是奇数和除数。
换句话说,这个解决方案相当于:
if ( n is odd )
m = (n >> 1) * (n + 1);
else
m = ( (n + 1) >> 1) * n;
答案 2 :(得分:3)
最简单的解决方案可能是使用更大的中间类型:
int m = (int)((long long)n * (n + 1) / 2) ;
由于自动类型提升将适用,因此无需投射所有操作数。
答案 3 :(得分:1)
还有一个:
int m = (n/2 * n) + ((n%2) * (n/2)) + (n/2) + (n%2);
答案 4 :(得分:1)
也许
result = (n) * (n / 2) + (n & 1) * (n) + n / 2 ;