给定整数值x
和y
,C和C ++都将商返回q = x/y
浮点等效项的下限。我对返回上限的方法感兴趣。例如ceil(10/5)=2
和ceil(11/5)=3
。
显而易见的方法包括:
q = x / y;
if (q * y < x) ++q;
这需要额外的比较和乘法。我见过的(实际上使用过的)其他方法都涉及将as float
或as强制转换double
。有没有更直接的方法来避免额外的乘法(或第二除法)和分支,并且还避免将其转换为浮点数?
给定整数值x
和y
,C和C ++都将商返回q = x/y
浮点等效项的下限。我对返回上限的方法感兴趣。例如ceil(10/5)=2
和ceil(11/5)=3
。
显而易见的方法包括:
q = x / y;
if (q * y < x) ++q;
这需要额外的比较和乘法。我见过的(实际上使用过的)其他方法都涉及将as float
或as强制转换double
。有没有更直接的方法来避免额外的乘法(或第二除法)和分支,并且还避免将其转换为浮点数?
Answers:
对于正数
unsigned int x, y, q;
舍入...
q = (x + y - 1) / y;
或(避免x + y中的溢出)
q = 1 + ((x - 1) / y); // if x != 0
x/y
除法的上限也是如此。C90没有指定如何舍入,我也不认为当前的C ++标准也可以。
q = x / y;
Sparky的答案是解决此问题的一种标准方法,但是正如我在评论中所写的那样,您还存在溢出的风险。这可以通过使用更广泛的类型来解决,但是如果要除以long long
s怎么办?
内森·恩斯特(Nathan Ernst)的答案提供了一种解决方案,但是它涉及到函数调用,变量声明和条件操作,这使其不比OPs代码短,甚至可能更慢,因为它难以优化。
我的解决方案是这样的:
q = (x % y) ? x / y + 1 : x / y;
这将比OPs代码快一点,因为模和除法是在处理器上使用相同的指令执行的,因为编译器可以看到它们是等效的。至少gcc 4.4.1使用x86上的-O2标志执行此优化。
从理论上讲,编译器可能会内森恩斯特(Nathan Ernst)的代码内联函数调用并发出相同的内容,但是当我测试它时,gcc并没有这样做。这可能是因为它将编译后的代码绑定到标准库的单个版本。
最后要注意的是,在现代计算机上,这一切都不重要,除非您处于非常紧密的循环中,并且所有数据都位于寄存器或L1缓存中。否则,除了Nathan Ernst的解决方案之外,所有这些解决方案都将同样快,如果必须从主内存中提取函数,Nathan Ernst的解决方案可能会明显变慢。
q = (x > 0)? 1 + (x - 1)/y: (x / y);
q = x / y + (x % y > 0);
比? :
表达容易吗?
您可以使用div
cstdlib中的函数在一次调用中获得商和余数,然后分别处理上限,如下所示
#include <cstdlib>
#include <iostream>
int div_ceil(int numerator, int denominator)
{
std::div_t res = std::div(numerator, denominator);
return res.rem ? (res.quot + 1) : res.quot;
}
int main(int, const char**)
{
std::cout << "10 / 5 = " << div_ceil(10, 5) << std::endl;
std::cout << "11 / 5 = " << div_ceil(11, 5) << std::endl;
return 0;
}
return res.quot + !!res.rem;
:)
这个怎么样?(要求y为非负数,因此在y是没有非负数保证的变量的极少数情况下,请勿使用此函数)
q = (x > 0)? 1 + (x - 1)/y: (x / y);
我简化y/y
为一个,消除了该术语,x + y - 1
并避免了溢出的可能性。
我避免x - 1
在when x
是无符号类型且包含零的情况下回绕。
对于有符号x
,负数和零仍然合并为一个大小写。
在现代通用CPU上,这可能不是一个巨大的好处,但是在嵌入式系统中,这比任何其他正确答案都快得多。
有一个解决方案,既可以解决正面问题,也可以解决负面问题,x
但是仅针对y
只有1个分区且没有分支的正面问题:
int ceil(int x, int y) {
return x / y + (x % y > 0);
}
请注意,如果x
为正,则除法接近零;如果提醒不为零,则应加1。
如果x
为负,则除法接近零,这就是我们所需要的,我们将不添加任何内容,因为x % y
不是正数
我本来想发表评论,但我的代表不够高。
据我所知,对于正参数和除数为2的幂,这是最快的方法(在CUDA中测试):
//example y=8
q = (x >> 3) + !!(x & 7);
仅对于一般肯定论点,我倾向于这样做:
q = x/y + !!(x % y);
q = x/y + !!(x % y);
抗衡q = x/y + (x % y == 0);
以及 q = (x + y - 1) / y;
解决方案在性能方面会很有趣。
简化的通用形式
int div_up(int n, int d) {
return n / d + (((n < 0) ^ (d > 0)) && (n % d));
} //i.e. +1 iff (not exact int && positive result)
为了获得更通用的答案,C ++函数使用定义明确的舍入策略进行整数除法
q = x/y + (x % y != 0);
足够了