【发布时间】:2017-06-11 18:29:13
【问题描述】:
需要对整数进行除法但将结果向上取整而不是向下取整是很常见的。一段时间以来,我一直在为那个小成语使用以下函数:
template <typename S, typename T>
constexpr inline S div_rounding_up(const S& dividend, const T& divisor)
{
return (dividend + divisor - 1) / divisor;
}
这有(至少)以下缺陷,或可能被视为缺陷:
- 虽然它对负操作数“按承诺”工作 - 它被称为
div_rounding_up- 让这种函数从零开始可能更有意义,因为x / y用于负值x和正值y向零舍入。换句话说,也许我应该实现的是div_rounding_away_from_zero,它可以与反转交换:让auto f = [&y](const S& x) { return div_rounding_away_from_zero(x,y); }我们将有f(-x) == -f(x)。 -
S的域末尾附近溢出。 -
sizeof(S) > sizeof(T)时可能出现奇怪的行为。 - 长函数名...
虽然您可以很容易地想到解决这些问题的方法,但它们会导致其他可能的缺陷,例如代码中的条件,或者依赖于计算可能很昂贵的模数。
那么有没有“正确的方法”来实现它?我所说的“正确”是指语义上令人愉悦、高效、避免上述许多缺陷,并有望被广泛使用。
注意事项:
- 如果您认为该函数应严格限制为只能使用非负参数,请说出来。恕我直言,这有点问题,因为我们不想将类型限制为无符号,而且我们不想检查操作数的符号。这似乎是我会使用联系人的东西 - 而 C++ 还没有。
- 在这里使用
std::div和变体是个好主意吗? - 性能比可读性更重要。最坏的情况是可以添加评论。
- 代码不应是特定于单一架构的(但如果您想为不同的架构使用 ifdef-else,那么请做我的客人)。
- 代码不应假定特定的编译器。
【问题讨论】:
-
不需要将除数和除数相加:将除数分配到该总和中。
-
@Bathsheba 如果我理解你的话,你的建议是否适用于整数除法?
-
对于不同类型的问题,也许你可以对两种类型都使用
T,并要求调用者传递相同的类型 -
@A.s.h.是的,因为你会从表达式中取出一个整数。
-
@M.M:我没这么说。只是对于负操作数,我想要/必须这样做是非常罕见的。
标签: c++ integer-division idioms rounding