将 64 位整数四舍五入为 32 位整数

Rounding 64 bit integers to 32 bit integers

我有一个函数可以进行舍入操作,如下所示。它以 64 位整数作为输入,并给出 32 位整数作为输出。转换时,将 0x40000000 的因子添加到输入中。背后的原因是什么?

int rounder(long long int in)
{
  INT64 out;
  if ((in >> 32) == 0x7FFFFFFF)
    out = in;
  else
    out = (INT64)0x40000000 + in; 
  out = out >> 31; 
  return (INT32)out;
}

输入似乎是一个带有 31 个小数位的 64 位定点数。如果小数部分 >= 0.5,则添加 0x40000000 值以向上舍入数字。 if 用于在四舍五入时避免可能的溢出。

让我们从一些较小的数字开始,因为它们更容易!

使用常规舍入,x.49999...或更小应向下舍入为 x,x.50000...或更多应向上舍入为 (x+1)。

(有lots种不同的舍入方法,但这是学校里学得最多的一种。)

无论何时进行整数除法(或将浮点值转换为整数),您只需丢弃小数部分。因此:

6/2 == 3.0  --> 3
5/2 == 2.5  --> 2

一个巧妙的 'trick' 是在除法之前加上除数的一半(在本例中为 1)。就像变魔术一样,您得到了正确的四舍五入!例如:

6/2  becomes  (6+1)/2  == 7/2 == 3.5  --> 3
5/2  becomes  (5+1)/2  == 6/2 == 3.0  --> 3

你可以通过这种方式了解它为什么有效:

 5/2  becomes  (5+1)/2  ==   5/2 + 1/2
13/6  becomes (13+3)/6  ==  13/6 + 3/6   == 13/6 + 1/2

您将真实答案加了一半。小于 x.5 的任何值仍将小于 x+1,因此仍会向下舍入,任何 x.5 或更大的值将变为 x+1 或更大,因此会向上舍入。

现在回答你的实际问题: 这个想法适用于所有除数;您向下移动 31,这与除以 2^31 相同。所以 'half-the-divisor' 是 2^30,或 0x40000000。

注意:正如其他人所指出的,此 'trick' 仅适用于正数(如果是负数则需要减去,但这是一堆蠕虫)。

这个话题有很多要考虑的;头脑清醒并不容易。一如既往,为自己尝试一些简单的例子,看看会发生什么。