实现整数除法的银行舍入

Aba*_*han 5 c embedded bankers-rounding rounding integer-division

在 C 语言中,最简单的实现公式是什么int divround(int a, int b) {...},其中输出为 a/b,并采用银行家四舍五入(四舍五入为偶数)?

例如,divround(3,2)两者divround(5,2)的计算结果均为 2。

我正在编写嵌入式代码,所以我不能依赖库。我希望代码对于 ARM 和 RISC-V 是通用的,所以也不需要汇编。我试图模仿np.around(a/b)NumPy 中的行为(它执行大约一半到偶数),因此我可以准确比较来自 Python 和我的嵌入式应用程序的输出测试向量。

dbu*_*ush 9

假设ab是非负数,并且b小于INT_MAX / 2,以下是一个简单的实现:

int divround(int a, int b)
{
    int q = a / b;
    int r = a % b;

    if (2*r > b) {
        return q + 1;
    } else if (2*r < b) {
        return q;
    } else if (q % 2 == 0) {
        return q;
    } else {
        return q + 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

解释一下:

  • 如果除法的余数大于b向上舍入的一半,如果小于向下舍入的一半。
  • 如果余数b/2正好,则检查商是否为偶数,如果是则向下舍入,否则向上舍入。

如果您还想处理负值,请首先确定结果的符号并将值标准化为非负,然后在将符号与结果相乘的同时执行上述操作。工作假设bINT_MIN / 2和之间INT_MAX / 2

int divround(int a, int b)
{
    int s_a = 1, s_b = 1;

    if (a < 0) {
        a = -a;
        s_a = -1;
    }
    if (b < 0) {
        b = -b;
        s_b = -1;
    }

    int q = a / b;
    int r = a % b;
    int sign = s_a * s_b;

    if (2*r > b) {
        return sign * (q + 1);
    } else if (2*r < b) {
        return sign * q;
    } else if (q % 2 == 0) {
        return sign * q;
    } else {
        return sign * (q + 1);
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,不要除以 0。

  • 无分支:`int q = a / b; int r = a % b * 2; 返回 q + ( (r==b)*(q%2) + (r&gt;b) );` `:-)` (2认同)