C ++函数用于整数除法,具有良好定义的舍入策略

时间:2011-11-15 13:21:42

标签: c++ c++11

我想要一些C ++中的东西,它允许我使用指定的舍入行为进行有效的整数除法,如下所示:

div_down(-4,3)        ==> -2
div_up(4,3)           ==> 2
div_to_zero(-4,3)     ==> -1
div_to_nearest(5,3)   ==> 2

我希望它能够在编译时检测目标机器的行为并生成适当的最佳实现。类似于模数的东西也会很好,在编译时抽象出负操作数的未定义行为。

这是否存在?

如果没有,有什么好办法呢?我可以想到几种可能的方法:

  • 尝试将它们实现为静态优化的单个表达式
  • 使用常量表达式来检测目标行为并从多个实现中进行选择,使用模板进行选择(但具体如何?)

3 个答案:

答案 0 :(得分:5)

这是我到目前为止所得到的,前提条件d>它们似乎都有效,但它们可以简化吗?

int div_down(int n, int d) {
  if (n < 0) {
    return -((d - n - 1) / d);
  } else {
    return n / d;
  }
}

int div_up(int n, int d) {
  if (n < 0) {
    return -(-n / d);
  } else {
    return (n + d - 1) / d;
  }
}

int div_to_zero(int n, int d) {
  return n / d;
}

int div_to_nearest(int n, int d) {
  if (n < 0) {
    return (n - d/2 + 1) / d;
  } else {
    return (n + d/2) / d;
  }
}

答案 1 :(得分:4)

一个旧帖子,但它就在这里。请接受&amp;如果你喜欢,请评价它。

int div_to_zero(int n, int d) { return n / d; }
//as per C++11 standard note 80

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)

int div_down(int n, int d) {
    return n / d - (((n > 0) ^ (d > 0)) && (n % d));
} //i.e. +1 iff (not exact int && negative result)

int div_to_nearest(int n, int d) {
    return (2*n - d + 2*(true&&(n<0^d>0))*d) / (2*d); 
} //i.e. +-0.5 as per pre-rounding result sign, then div_to-zero 
//it however rounds numbers like +/- 3.5 towards 0 and not even.

注意:大多数现代编译器将使用单个除法运算来同时使用n / d和n%d。因此,性能方面最好的是减少内存移动。

答案 2 :(得分:1)

C ++ 11的最后一个草案,n3242 几乎与实际的C ++ 11标准相同,在5.6分4(第118页)中说明了这一点:

  

对于积分操作数,/运算符产生代数商   丢弃任何小数部分; (见注80)

注意80个州(请注意,注释是非规范性的):

  

80)这通常被称为零截断。

为了完整起见,Point 4继续说明:

  

如果商a / b在结果类型中是可表示的,   (a / b)* b + a%b等于a。

可以证明a%b的符号与a的符号相同(非零时)。

注意:实际的C ++ 11标准不合法在线。但是,草案是。幸运的是,最后草案(N3242)与实际标准之间的差异很小。请参阅this answer

注意:我不确定哪些编译器符合C ++ 11标准。


所以div_to_zero()是常规的/部门。

对于其他功能,我担心你必须测试ab的迹象并进行相应的调整。有时,可能需要额外检查a%b是否等于零。因此,我们在这里查看每个函数的12个测试用例(3个符号或者是z的符号,b符号的时间为2,无论a%b是否等于0,时间为2)。

现在对我来说太过分了,所以也许别人会跳进去提供正确答案。

我知道我没有回答你的问题,但上面的信息似乎很有价值,而且太大而无法发表评论。