【问题标题】:Handling overflow in fraction multiplication处理分数乘法中的溢出
【发布时间】:2016-02-05 02:24:32
【问题描述】:

假设我想将x 乘以(3/8)。所以我可以使用移位操作得到结果如下(结果应该向零舍入):

int Test(int x) {
    int value = (x << 1) + x;
    value = value >> 3;
    value =  value + ((x >> 31) & 1); 
    return  value;
}

所以我将在Test(11) 中有4,在Test(-9) 中有-3。问题是,因为我先做乘法,所以在某些范围内会溢出,在这种情况下我不会得到正确的值:

Test(0x80000000)  // returns -268435455, but it should be -268435456

我该如何解决这个问题?

【问题讨论】:

  • 你已经在几天前发布了这个问题。我(和其他人)告诉过你你调用 undefinedimplementation defined behavior。并且溢出还会调用未定义的行为,所以所有的赌注都被取消了。
  • 您需要使用大于int 的变量,例如long 假设 long 在您的系统上有更多位。或者您可以将int 拆分为两个ints,每个都有一半的位,然后进行数学运算。
  • @user3386109: long 在 POSIX64 上只有更多位,并且不是真正可移植的。最好使用固定宽度类型。这些也有明确定义的表示,因此有符号/无符号的转换行为。
  • @Olaf 注意:除了 POSIX64 之外,许多系统的 long 都比 int 宽:嵌入式平台、DOS 等。
  • @Olaf 感谢您再次提及。请注意,未定义的行为并没有真正改变我的问题,这也不是同一个问题。我仍然想处理这个溢出(请阅读标题)。此外,由于我问了这个问题,这仅意味着您以前的 cmets 没有帮助。

标签: c bit-manipulation overflow


【解决方案1】:

我该如何解决这个问题? (在某些范围内溢出)

先除以 8。

对于 8 的每个倍数,结果恰好增加 3。所以剩下的就是找出 3/8 的数字 -7 到 7,OP 的 test() 可以处理。可能的简化。

int Times3_8(int x) {
  int div8 = x/8;
  int value = div8*3 + Test(x%8);
} 

【讨论】:

    【解决方案2】:

    一种解决方案是以不同方式处理高半部分和低半部分。对于x 的高半部分,先右移 3,然后乘以 3。对于低半部分,先乘以 3,然后再右移 3。然后将两个结果相加。这应该适用于积极的情况。对于负数,您需要稍微调整一下。

    【讨论】:

      【解决方案3】:
      int foo(int x)
      {
          return x/8*3 + x%8*3/8;
      }
      

      http://ideone.com/2wGtpl

      chux 的回答启发:关键是先除以 8(牺牲范围的精度),然后使用第二项来处理量化误差(纠正较小的误差范围)。

      【讨论】:

        猜你喜欢
        • 2015-03-30
        • 2017-02-13
        • 1970-01-01
        • 2020-06-12
        • 2014-05-21
        • 2015-08-16
        • 2015-04-11
        • 2011-03-11
        • 1970-01-01
        相关资源
        最近更新 更多