将除法结果四舍五入为最接近的整数是pretty simple。但是,我正在尝试对除法结果进行四舍五入,以使后续操作能够给出最佳近似值。最好用一个简单的函数来解释:

const int halfbits = std::numeric_limits<unsigned int>::digits / 2;
unsigned x = foo(); // Likely big.
unsigned x_div = x >> halfbits; // Rounded down
unsigned y = x_div * x_div; // Will fit due to division.

我可以通过添加x_div1<<(halfbits-1)舍入到最接近的值。但是由于x²不是线性函数,因此y通常不会正确舍入。有没有一种简单且更准确的方法来计算(x*x) >> (halfbits*2)而无需使用更大的类型?

我认为将3<<(halfbits-3)添加到x_div可以改善舍入效果,但不能证明这是最佳解决方案。另外,可以将其推广到xⁿ吗?

编辑:出于普遍需求,我自由地使用纯算术术语来“翻译”问题(这些C位移位都不是...)。
注意:此后所有除法都是整数除法,例如13/3将为4。
问题:因为x大,所以我们无法计算x ^ 2,因此我们想计算(x ^ 2)/(2 ^ N)。
为此,我们计算
x_div = x/sqrt(2 ^ N)
然后我们将其平方:
y = x_div * x_div

但是,此结果通常缺少(x^2)/(2^N)的确切值,OP建议添加0.5 * sqrt(2 ^ N)或0.375 * sqrt(2 ^ N)以便更好地近似结果。

正如Oli Charlesworth的答案所暗示的那样,通过将x^2视为(x_hi + x_lo)^ 2,有一种更好的方法来获取实际值。

最佳答案

而使用x_div截断将导致错误幅度最大为1,而使用x_div*x_div时,错误可能高达1<<(half_digits+2)

要了解原因,请考虑我们可以如下表示平方(使用long multplication):

x * x = (x_lo + x_hi) * (x_lo + x_hi)
      = x_lo^2 + x_hi^2 + 2*x_lo*x_hi

其中x_lox_hi分别是x的下半部分和上半部分。借助一些不错的ASCII艺术,我们可以考虑所有这些如何排列:
 MSB     :      :      :     LSB
  +------+------+      :      :
  |    x_hi^2   |      :      :
  +-----++-----++-----+:      :
  :     | 2*x_lo*x_hi |:      :
  :     +------++-----++------+
  :      :      |    x_lo^2   |
  :      :      +------+------+
  :<----------->:      :      :
    Our result

如我们所见,低阶项会影​​响最终结果中的多个位。

但是,这些术语中的每一个都应适合原始类型,而不会发生溢出。因此,通过适当的移位和 mask ,我们可以获得所需的结果。

当然,如果使用更大的类型,则编译器/硬件会为您完成所有操作,因此,如果可以选择,则应该这样做。

关于c++ - 将y = x * x舍入到最接近的值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15758926/

10-13 04:34