将除法结果舍入到最接近的整数是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)
而不使用更大的类型?
我认为向x_div添加3<<(halfbits-3)
会改进舍入,但无法证明这是最佳解决方案。此外,这可以推广为xⁿ?
编辑:按照大众的要求,我冒昧地用纯算术术语“翻译”这个问题(这些C改变的东西都不是......)。
注意:此后的所有除法都是整数除数,例如13/3将是4
问题:我们无法计算x ^ 2因为x很大,所以我们想要计算(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,可以更好地获得实际值。
答案 0 :(得分:8)
使用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
正如我们所看到的,低阶项会影响最终结果中的多个位。
但是,这些术语中的每一个都应该适合原始类型而不会溢出。因此,通过适当的移动和屏蔽,我们可以获得所需的结果。
当然,如果您使用更大的类型,编译器/硬件会为您完成所有操作,因此如果您有选项,则应该这样做。
答案 1 :(得分:-4)
将TYPE int用于“y”。我想这可以解决目的。