安全地四舍五入到下一个较小的倍数

Safely round to next smaller multiple

本文关键字:下一个 四舍五入 安全      更新时间:2023-10-16

考虑:

int a, b;
int c = b * (a / b)

我认为应该很清楚它对正数的作用:c被设置为b的倍数,后者相对于a较小。

示例:设b = 2,则:

a = 0 => c = 0
a = 1 => c = 0
a = 2 => c = 2
a = 3 => c = 2

然而,对于负数,它的工作方式正好相反:它取b的下一个较大(较负)倍数。同时取b的第二个较小(较负的)倍数的最佳方法是什么

怎么样:

#include <cstdlib>
#include <iostream>
int round_down(int val, int unit) {
  std::div_t div_result = std::div(val, unit);
  int candidate = div_result.quot * unit;
  return candidate <= val ? candidate : 
         unit >= 0 ? candidate - unit :
         candidate + unit;
}
int main() {
  std::cout << round_down(9, 7) << std::endl;
  std::cout << round_down(13, 2) << std::endl;
  std::cout << round_down(15, 3) << std::endl;
  std::cout << round_down(-9, 7) << std::endl;
  std::cout << round_down(-13, 2) << std::endl;
  std::cout << round_down(-15, 3) << std::endl;
  std::cout << round_down(9, -7) << std::endl;
  std::cout << round_down(13, -2) << std::endl;
  std::cout << round_down(15, -3) << std::endl;
  std::cout << round_down(-9, -7) << std::endl;
  std::cout << round_down(-13, -2) << std::endl;
  std::cout << round_down(-15, -3) << std::endl;
}

注意,在C++11之前,内置除法运算符/的舍入方向是实现定义的。因此,我使用std::div()。引用自cppreference(强调矿):

二进制运算符将第一个操作数除以第二个操作数(之后通常的算术转换)
对于整数操作数,它产生代数商
商按实现定义的方向四舍五入。(直到C++11)
商为向零截断(丢弃小数部分)。(从C++11开始)

注意:在C++11之前,如果一个或两个操作数都为二进制运算符%为负,剩余部分的符号为实现定义,因为它取决于整数除法的舍入方向函数std::div在这种情况下提供了定义良好的行为

如果a<0,您只需要从a中减去b+1,然后将其传递给您的函数:

#include <iostream>
using namespace std;
int main()
{
    cout << "---------------------------------" << endl;
    for (int bi = 1; bi < 10; bi++)
    {
        for (int ai = -10; ai < 10; ai++)
        {
            int a = ai;
            int b = bi;
            if (a < 0)
                a -= b + 1;
            int c = b * (std::div(a / b));
            cout << "a = " << a << ",b = " << b << " => c = " << c << endl;
        }
        cout << "---------------------------------" << endl;
    }
}

输出:

---------------------------------
a = -12,b = 1 => c = -12
a = -11,b = 1 => c = -11
a = -10,b = 1 => c = -10
a = -9,b = 1 => c = -9
a = -8,b = 1 => c = -8
a = -7,b = 1 => c = -7
a = -6,b = 1 => c = -6
a = -5,b = 1 => c = -5
a = -4,b = 1 => c = -4
a = -3,b = 1 => c = -3
a = 0,b = 1 => c = 0
a = 1,b = 1 => c = 1
a = 2,b = 1 => c = 2
a = 3,b = 1 => c = 3
a = 4,b = 1 => c = 4
a = 5,b = 1 => c = 5
a = 6,b = 1 => c = 6
a = 7,b = 1 => c = 7
a = 8,b = 1 => c = 8
a = 9,b = 1 => c = 9
---------------------------------
a = -13,b = 2 => c = -12
a = -12,b = 2 => c = -12
a = -11,b = 2 => c = -10
a = -10,b = 2 => c = -10
a = -9,b = 2 => c = -8
a = -8,b = 2 => c = -8
a = -7,b = 2 => c = -6
a = -6,b = 2 => c = -6
a = -5,b = 2 => c = -4
a = -4,b = 2 => c = -4
a = 0,b = 2 => c = 0
a = 1,b = 2 => c = 0
a = 2,b = 2 => c = 2
a = 3,b = 2 => c = 2
a = 4,b = 2 => c = 4
a = 5,b = 2 => c = 4
a = 6,b = 2 => c = 6
a = 7,b = 2 => c = 6
a = 8,b = 2 => c = 8
a = 9,b = 2 => c = 8
---------------------------------
a = -14,b = 3 => c = -12
a = -13,b = 3 => c = -12
a = -12,b = 3 => c = -12
a = -11,b = 3 => c = -9
a = -10,b = 3 => c = -9
a = -9,b = 3 => c = -9
a = -8,b = 3 => c = -6
a = -7,b = 3 => c = -6
a = -6,b = 3 => c = -6
a = -5,b = 3 => c = -3
a = 0,b = 3 => c = 0
a = 1,b = 3 => c = 0
a = 2,b = 3 => c = 0
a = 3,b = 3 => c = 3
a = 4,b = 3 => c = 3
a = 5,b = 3 => c = 3
a = 6,b = 3 => c = 6
a = 7,b = 3 => c = 6
a = 8,b = 3 => c = 6
a = 9,b = 3 => c = 9
---------------------------------
a = -15,b = 4 => c = -12
a = -14,b = 4 => c = -12
a = -13,b = 4 => c = -12
a = -12,b = 4 => c = -12
a = -11,b = 4 => c = -8
a = -10,b = 4 => c = -8
a = -9,b = 4 => c = -8
a = -8,b = 4 => c = -8
a = -7,b = 4 => c = -4
a = -6,b = 4 => c = -4
a = 0,b = 4 => c = 0
a = 1,b = 4 => c = 0
a = 2,b = 4 => c = 0
a = 3,b = 4 => c = 0
a = 4,b = 4 => c = 4
a = 5,b = 4 => c = 4
a = 6,b = 4 => c = 4
a = 7,b = 4 => c = 4
a = 8,b = 4 => c = 8
a = 9,b = 4 => c = 8
---------------------------------
a = -16,b = 5 => c = -15
a = -15,b = 5 => c = -15
a = -14,b = 5 => c = -10
a = -13,b = 5 => c = -10
a = -12,b = 5 => c = -10
a = -11,b = 5 => c = -10
a = -10,b = 5 => c = -10
a = -9,b = 5 => c = -5
a = -8,b = 5 => c = -5
a = -7,b = 5 => c = -5
a = 0,b = 5 => c = 0
a = 1,b = 5 => c = 0
a = 2,b = 5 => c = 0
a = 3,b = 5 => c = 0
a = 4,b = 5 => c = 0
a = 5,b = 5 => c = 5
a = 6,b = 5 => c = 5
a = 7,b = 5 => c = 5
a = 8,b = 5 => c = 5
a = 9,b = 5 => c = 5
---------------------------------
a = -17,b = 6 => c = -12
a = -16,b = 6 => c = -12
a = -15,b = 6 => c = -12
a = -14,b = 6 => c = -12
a = -13,b = 6 => c = -12
a = -12,b = 6 => c = -12
a = -11,b = 6 => c = -6
a = -10,b = 6 => c = -6
a = -9,b = 6 => c = -6
a = -8,b = 6 => c = -6
a = 0,b = 6 => c = 0
a = 1,b = 6 => c = 0
a = 2,b = 6 => c = 0
a = 3,b = 6 => c = 0
a = 4,b = 6 => c = 0
a = 5,b = 6 => c = 0
a = 6,b = 6 => c = 6
a = 7,b = 6 => c = 6
a = 8,b = 6 => c = 6
a = 9,b = 6 => c = 6
---------------------------------
a = -18,b = 7 => c = -14
a = -17,b = 7 => c = -14
a = -16,b = 7 => c = -14
a = -15,b = 7 => c = -14
a = -14,b = 7 => c = -14
a = -13,b = 7 => c = -7
a = -12,b = 7 => c = -7
a = -11,b = 7 => c = -7
a = -10,b = 7 => c = -7
a = -9,b = 7 => c = -7
a = 0,b = 7 => c = 0
a = 1,b = 7 => c = 0
a = 2,b = 7 => c = 0
a = 3,b = 7 => c = 0
a = 4,b = 7 => c = 0
a = 5,b = 7 => c = 0
a = 6,b = 7 => c = 0
a = 7,b = 7 => c = 7
a = 8,b = 7 => c = 7
a = 9,b = 7 => c = 7
---------------------------------
a = -19,b = 8 => c = -16
a = -18,b = 8 => c = -16
a = -17,b = 8 => c = -16
a = -16,b = 8 => c = -16
a = -15,b = 8 => c = -8
a = -14,b = 8 => c = -8
a = -13,b = 8 => c = -8
a = -12,b = 8 => c = -8
a = -11,b = 8 => c = -8
a = -10,b = 8 => c = -8
a = 0,b = 8 => c = 0
a = 1,b = 8 => c = 0
a = 2,b = 8 => c = 0
a = 3,b = 8 => c = 0
a = 4,b = 8 => c = 0
a = 5,b = 8 => c = 0
a = 6,b = 8 => c = 0
a = 7,b = 8 => c = 0
a = 8,b = 8 => c = 8
a = 9,b = 8 => c = 8
---------------------------------
a = -20,b = 9 => c = -18
a = -19,b = 9 => c = -18
a = -18,b = 9 => c = -18
a = -17,b = 9 => c = -9
a = -16,b = 9 => c = -9
a = -15,b = 9 => c = -9
a = -14,b = 9 => c = -9
a = -13,b = 9 => c = -9
a = -12,b = 9 => c = -9
a = -11,b = 9 => c = -9
a = 0,b = 9 => c = 0
a = 1,b = 9 => c = 0
a = 2,b = 9 => c = 0
a = 3,b = 9 => c = 0
a = 4,b = 9 => c = 0
a = 5,b = 9 => c = 0
a = 6,b = 9 => c = 0
a = 7,b = 9 => c = 0
a = 8,b = 9 => c = 0
a = 9,b = 9 => c = 9
---------------------------------

您引用的代码的行为实际上是正确的。负整数除法的定义是这样的,对于mn是正整数,以下是真的:

-(m)/n=-(m/n)

因此,我在这里假设,你实际上在问的是如何获得:

a = -1 => c = -2
a = -2 => c = -2
a = -3 => c = -4
a = -4 => c = -4
a = -5 => c = -6

在这种情况下,不要使用整数除法,这不是您想要的。你想要的是浮点除法的地板。幸运的是,有楼层功能可以帮你做这件事。试试这个:

int c = b * floor((double)a / (double)b);

它应该给你想要的东西。