将除法结果四舍五入为最接近的整数是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_div
将1<<(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_lo
和x_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/