In C bits, multiply by 3 and divide by 16

后端 未结 5 599
孤独总比滥情好
孤独总比滥情好 2020-12-29 17:46

A buddy of mine had these puzzles and this is one that is eluding me. Here is the problem, you are given a number and you want to return that number times 3 and divided by 1

5条回答
  •  醉梦人生
    2020-12-29 17:49

    Note that the C99 standard states in section section 6.5.7 that right shifts of signed negative integer invokes implementation-defined behavior. Under the provisions that int is comprised of 32 bits and that right shifting of signed integers maps to an arithmetic shift instruction, the following code works for all int inputs. A fully portable solution that also fulfills the requirements set out in the question may be possible, but I cannot think of one right now.

    My basic idea is to split the number into high and low bits to prevent intermediate overflow. The high bits are divided by 16 first (this is an exact operation), then multiplied by three. The low bits are first multiplied by three, then divided by 16. Since arithmetic right shift rounds towards negative infinity instead of towards zero like integer division, a correction needs to be applied to the right shift for negative numbers. For a right shift by N, one needs to add 2N-1 prior to the shift if the number to be shifted is negative.

    #include 
    #include 
    
    int ref (int a)
    {
      long long int t = ((long long int)a * 3) / 16;
      return (int)t;
    }
    
    int main (void)
    {
      int a, t, r, c, res;
      a = 0;
      do {
        t = a >> 4;         /* high order bits */
        r = a & 0xf;        /* low order bits */
        c = (a >> 31) & 15; /* shift correction. Portable alternative: (a < 0) ? 15 : 0 */
        res = t + t + t + ((r + r + r + c) >> 4);
        if (res != ref(a)) {
          printf ("!!!! error a=%08x  res=%08x  ref=%08x\n", a, res, ref(a));
          return EXIT_FAILURE;
        }
        a++;
      } while (a);
      return EXIT_SUCCESS;
    }
    

提交回复
热议问题