0

在 ac 程序中,我有一个 long long int 类型的变量,它存储一个值 0x7fffffffffffffff。当我将此值除以 1024 * 4 时,它给了我 2251799813685247 即 0x7ffffffffffff。

现在,当我乘回 (1024 * 4) 时,结果为 0x7ffffffffffff000。

即使我创建了 long long unsigned int 类型的变量,结果也没有变化。代码在 64 位机器上运行。

为什么它不会导致 0x7fffffffffffffff?

4

4 回答 4

7

如果你将它除以 4096,那只是右移 12 位。这意味着最后 12 位丢失:

0x7fffffffffffffff becomes
0x7ffffffffffff

如果你乘回来,你左移 12,所以缺失的位用 0 填充。

于 2013-11-14T08:24:38.573 回答
1

只要结果符合类型的范围,整数除法和整数乘法都可以正常工作。如果没有,你会得到各种截断等。

让我们得到一个更简单的版本,一个 char 变量 [0-255]

  unsigned char a = 12;
  unsigned char b = a/4;

因为 12/4 = 3 正好,并且 3 是一个介于 0 和 255 之间的整数,b所以是 3。将它乘以 4,你得到你的 12。

  unsigned char a = 11;
  unsigned char b = a/2;

11/2 是 5.5 但整数不能存储小数部分。在这种情况下,b 是5并且 0.5 部分不可恢复地丢失。乘以b2 你得到10,不是11

请注意,它是截断,而不是四舍五入。

  unsigned char a = 100;
  unsigned char b = a/15;

100/15 是 6.66(6) - 四舍五入到最接近的整数将更接近 7。问题是,我们正在截断,而不是四舍五入,所以 (int) 6.6666666666 是 6。小数部分永远丢失。现在将 b*15 相乘得到 90。这相差甚远——这是使用整数而不是浮点数的代价。

更糟糕的事情发生在溢出中。

  unsigned char a = 150;
  unsigned char b = a*2;  //300 with top bit truncated becomes 44
  unsigned char c = b/2;  // 44/2 = 22

但这是另一个问题的主题。

于 2013-11-14T10:23:51.543 回答
1
echo "((15/4)*4)" | bc

结果不是 15

于 2013-11-14T09:06:45.720 回答
0

它的简单数学...

1024 * 4 * 0x7ffffffffffff = 0x7ffffffffffff000

于 2013-11-14T08:26:26.993 回答