处理分数乘法中的溢出

时间:2016-02-05 02:24:33

标签: c bit-manipulation overflow

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

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

所以我4 Test(11)-3 Test(-9) Test(0x80000000) // returns -268435455, but it should be -268435456 。问题是,因为我首先进行乘法,所以在某些范围内会出现溢出,在这种情况下,我不会得到正确的值:

  12:54:39.859 [main] INFO  org.reflections.Reflections - Reflections took 63 ms to scan 1 urls, producing 73 keys and 122 values
  12:54:39.906 [main] DEBUG i.s.jaxrs.ext.SwaggerExtensions - adding extension io.swagger.jersey.SwaggerJersey2Jaxrs@18be6e8
  12:54:39.906 [main] DEBUG io.swagger.jaxrs.Reader - picking up response class from method public rest.beans.UserBean rest.frontend.UserResource.opAllocateUser(rest.beans.UserBean,javax.ws.rs.core.Request)
  12:54:39.921 [main] DEBUG i.s.c.ModelConverterContextImpl - resolveProperty class  rest.beans.UserBean
  12:54:39.921 [main] DEBUG io.swagger.jackson.ModelResolver - resolveProperty [simple type, class  rest.beans.UserBean]
  12:54:39.921 [main] DEBUG i.s.c.ModelConverterContextImpl - resolve [simple type, class  rest.beans.UserBean]
  12:54:39.921 [main] DEBUG i.s.c.ModelConverterContextImpl - trying extension io.swagger.jackson.ModelResolver@5ecce3
  12:54:39.921 [main] DEBUG io.swagger.jackson.ModelResolver - Can't check class [simple type, class  rest.beans.UserBean],        rest.beans.UserBean
  12:54:39.937 [main] DEBUG i.s.c.ModelConverterContextImpl - defineModel UserBean io.swagger.models.ModelImpl@c2b00fee
  12:54:39.937 [main] DEBUG i.s.c.ModelConverterContextImpl - resolveProperty [simple type, class java.lang.String]
  12:54:39.937 [main] DEBUG io.swagger.jackson.ModelResolver - Can't check class [simple type, class java.lang.String], java.lang.String
  12:54:39.952 [main] DEBUG io.swagger.jackson.ModelResolver - resolveProperty [simple type, class java.lang.String]
  12:54:39.952 [main] DEBUG i.s.c.ModelConverterContextImpl - resolveProperty [simple type, class java.lang.String]
  12:54:39.952 [main] DEBUG io.swagger.jackson.ModelResolver - Can't check class [simple type, class java.lang.String], java.lang.String
  12:54:39.952 [main] DEBUG io.swagger.jackson.ModelResolver - resolveProperty [simple type, class java.lang.String]
  12:54:39.952 [main] DEBUG io.swagger.converter.ModelConverters - ModelConverters readAll from class  rest.beans.UserBean
  12:54:39.952 [main] DEBUG i.s.c.ModelConverterContextImpl - resolve class  rest.beans.UserBean
  12:54:39.952 [main] DEBUG i.s.c.ModelConverterContextImpl - trying extension io.swagger.jackson.ModelResolver@5ecce3
  12:54:39.952 [main] DEBUG i.s.c.ModelConverterContextImpl - defineModel UserBean io.swagger.models.ModelImpl@c2b00fee
  12:54:39.952 [main] DEBUG i.s.c.ModelConverterContextImpl - resolveProperty [simple type, class java.lang.String]
  12:54:39.952 [main] DEBUG io.swagger.jackson.ModelResolver - Can't check class [simple type, class java.lang.String], java.lang.String
  12:54:39.952 [main] DEBUG io.swagger.jackson.ModelResolver - resolveProperty [simple type, class java.lang.String]
  12:54:39.952 [main] DEBUG i.s.c.ModelConverterContextImpl - resolveProperty [simple type, class java.lang.String]
  12:54:39.952 [main] DEBUG io.swagger.jackson.ModelResolver - Can't check class [simple type, class java.lang.String], java.lang.String
  12:54:39.952 [main] DEBUG io.swagger.jackson.ModelResolver - resolveProperty [simple type, class java.lang.String]
  12:54:39.952 [main] DEBUG io.swagger.jaxrs.Reader - getParameters for [simple type, class  rest.beans.UserBean]
  12:54:39.952 [main] DEBUG io.swagger.jaxrs.Reader - trying extension io.swagger.jersey.SwaggerJersey2Jaxrs@18be6e8

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

  

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

首先除以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);
} 

答案 1 :(得分:0)

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

答案 2 :(得分:0)

int foo(int x)
{
    return x/8*3 + x%8*3/8;
}

http://ideone.com/2wGtpl

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