我需要对这个按位难题进行一些解释

问题描述

我被这个难题困扰了几个小时。我在Google上寻找解决此问题的好方法,以了解其他人如何解决它,而我遇到了该解决方案。我试图弄清楚它是如何工作的。我对此唯一不了解的是四舍五入过程和丢失的位?丢了什么?

我非常感谢有人向我解释此解决方案。

预先感谢你们,优胜美地:)

/*
 * ezThreeFourths - multiplies by 3/4 rounding toward 0,*   Should exactly duplicate effect of C expression (x*3/4),*   including overflow behavior.
 *   Examples: ezThreeFourths(11) = 8
 *             ezThreeFourths(-9) = -6
 *             ezThreeFourths(1073741824) = -268435456 (overflow)
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 3
 */

int ezThreeFourths(int x) {
/*
 *sets y to make up for the lost bits while rounding. Multiplies
 *by three by adding x 3 times. Records the sign since
 * what is added will be different depending on whether the sign
 *is positive or negative and adds this to to the number. Then
 *divedes by 8 by shifting.
 */
  int y = 3;
  x =x+x+x;
  int z = x>>31;
  z = y & z;
  x = z + x;
  x = x>>2;
  return x;
}

这是我从以下位置获得的链接:link该个人没有在文件中标记他的名字,所以我不知道他的名字

解决方法

在这里所做的所有工作都是为了匹配iso C定义除法向零取整的事实。乘以3/4的方法更简单,就是乘以3并乘以2:

return (x+x+x) >> 2;

不幸的是,它具有wrong behaviour表示负值(它将底数减小而不是四舍五入)。

要解决此问题,我们需要在负数项前添加3 * ,然后再将其移位2以通过截断模拟舍入。我们这样做如下:

int z = x >> 31; // Arithmetic right shift extracts sign mask (0xffffffff or 0x0)
int y = 3 & z; // 3 for negative values,0 for nonnegative
return (x + x + x + y) >> 2; // Multiply and divide with rounding

更正确地说,我们应该考虑到通过更改代码,我们实际上并不知道整数的大小为32:

int three_fourths(int x) {
    return (x + x + x + (3 & (x >> (8 * sizeof(x) - 1)))) >> 2;
}

您可以在操作here中看到此最终实现。

* 这是将地板分隔线变成天花板分隔线的惯用法。如果您将x / N向下舍入,则可以将表达式更改为(x + N - 1) / N来向上舍入。对于N==4,转换将为x / 4-> (x + 3) / 4


未定义的行为

我们终于有了一些假设。当然,x + x + x可能会溢出并产生未定义的行为,但这与x * 3没什么不同(忽略问题作者的建议,即溢出具有相同的行为,它将在某些实现上得到保证,但这不能保证)。 / p>

实现定义的行为的最大部分是算术右移。这是C标准在此问题上必须说的(ISO/IEC 9899:TC3§6.5.7¶5):

E1 >> E2的结果是E1个右移E2位的位置。如果E1 具有未签名的类型 或如果E1具有带符号的类型和非负值,则结果的值是整数 E1 / 2 E2 的商的一部分。如果E1具有带符号的类型和负值,则 结果值是实现定义的。

因此,仅当将任何负值右移小于int宽度的值时,才产生掩码值,掩码值提取仅在所有位位置中都产生一个带有一个值的值。在common implementation中,这适用于二进制补码系统(可能还有您将使用的任何系统),但是该标准在技术上不能保证。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...