7

Using only:

! ~ & ^ | + << >>

I need to find out if a signed 32 bit integer can be represented as a 16 bit, two's complement integer.

My first thoughts were to separate the MSB 16 bits and the LSB 16 bits and then use a mask to and the last 16 bits so if its not zero, it wont be able to be represented and then use that number to check the MSB bits.

An example of the function I need to write is: fitsInShort(33000) = 0 (cant be represented) and fitsInShort(-32768) = 1 (can be represented)

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Vishal
  • 73
  • 1
  • 3

5 Answers5

8

If a 32-bit number is in the range [-32768,+32767], then the 17 msbs will all be the same.

Here's a crappy way of telling if a 3-bit number is all ones or all zeros using only your operations (I'm assuming that you're not allowed conditional control structures, because they require implicit logical operations):

int allOnes3(int x)
{
    return ((x >> 0) & (x >> 1) & (x >> 2)) & 1;
}

int allTheSame3(int x)
{
    return allOnes3(x) | allOnes3(~x);
}

I'll leave you to extend/improve this concept.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
8
bool fits16(int x)
{
    short y = x;
    return y == x;
}

Just kidding :) Here's the real answer, assuming int is 32 bits and short is 16 bits and two's complement represantation:

Edit: Please see the last edit for the correct answer!

bool fits16(int x)
{
    /* Mask out the least significant word */
    int y = x & 0xffff0000;
    if (x & 0x00008000) {
        return y == 0xffff0000;
    } else {
        return y == 0;
    }
}

Without if statements i beleive that should do it:

return (
    !(!(x & 0xffff0000) || !(x & 0x00008000)) ||
    !((x & 0xffff0000) || (x & 0x00008000))
);

Edit: Oli's right. I somehow thought that they were allowed. Here's the last attempt, with explanation:

We need the 17 most significant bits of x to be either all ones or all zeroes. So let's start by masking other bits out:

int a = x & 0xffff8000; // we need a to be either 0xffff8000 or 0x00000000
int b = a + 0x00008000; // if a == 0xffff8000 then b is now 0x00000000
                        // if a == 0x00000000 then b is now 0x00008000
                        // in any other case b has a different value
int c = b & 0xffff7fff; // all zeroes if it fits, something else if it doesn't
return c;

Or more concisely:

return ((x & 0xffff8000) + 0x8000) & 0xffff7fff;
cyco130
  • 4,654
  • 25
  • 34
  • I cant use if statements either. I need something that is all 0's for it fits and something else for it not fitting so I can just ! the number and get a 0 or 1. – Vishal Sep 07 '11 at 17:08
  • Just edited. If I remember correctly !(!a || !b) == (a && b). or something like this... – cyco130 Sep 07 '11 at 17:25
  • 2
    The OP doesn't mention logical operators (`&&`, `||`). – Oliver Charlesworth Sep 07 '11 at 19:49
  • @Vishal: You've accepted this answer, but you don't mention logical operators (`&&` or `||`) in your question. – Oliver Charlesworth Sep 07 '11 at 20:52
  • 1
    So last case answer 0 if it fits which is the negation (doesntFit16) and it has one unecessary operation. I would just write #define fits16(x) (!(((unsigned)(x)+0x8000U) & OxFFFF0000U)) – aka.nice Jan 30 '13 at 00:57
3

Here's a solution without casting, if-statements and using only the operators you asked for:

#define fitsInShort(x) !(((((x) & 0xffff8000) >> 15) + 1) & 0x1fffe)
Emil Romanus
  • 794
  • 1
  • 4
  • 8
  • Smart answer. It would help the asker if you could explain why it works :) – qdot Sep 08 '11 at 14:40
  • I noticed that the accepted answerer took my idea and added it to his answer after having been accepted already. Would have been shameful if it was not for the fact that he improved it. The bitshifting is unnecessary and can be replaced by + 0x8000 and another mask. Please see his explanation of why this works. The basic idea is to isolate the bits that should be either all 0 or all 1, and then add +1. If the number fits, that must be either (-1)+1 or 0+1, so if the resulting number & 0xfffe is 0 (disregarding the last bit), then the number fits. – Emil Romanus Sep 08 '11 at 15:40
0
if (!(integer_32 & 0x8000000))
{
   /* if +ve number */
  if (integer_32 & 0xffff8000)
    /* cannot fit */
  else 
    /* can fit */
}
else if (integer_32 & 0x80000000)
{
  /* if -ve number */
  if ( ~((integer_32 & 0xffff8000) | 0x00007fff))
    /* cannot fit */
  else
    /* can fit */
}

First if Checks for +ve number first by checking the signed bit. If +ve , then it checks if the bit 15 to bit 31 are 0, if 0, then it cannot fit into short, else it can.

The negative number is withing range if bit 15 to 31 are all set (2's complement method representation).

Therefore The second if it is a -ve number, then the bit 15 to 31 are masked out and the remaining lower bits (0 to 14) are set. If this is 0xffffffff then only the one's complement will be 0, which indicates the bit 15 to 31 are all set, therefore it can fit (the else part), otherwise it cannot fit (the if condition).

phoxis
  • 60,131
  • 14
  • 81
  • 117
0
short fitsInShort(int x)
{
    int positiveShortRange = (int) ((short) 0xffff / (short) 2);
    int negativeShortRange = (int) ((short) 0xffff / (short) 2) + 1;

    if(x > negativeShortRange && x < positiveShortRange)
        return (short) x;
    else
        return (short) 0;
}
BlackBear
  • 22,411
  • 10
  • 48
  • 86