如果x * x可以容纳32位整数,如何返回1,否则返回0?

时间:2018-10-12 20:41:33

标签: c binary bit-manipulation bitwise-operators

我正在研究一个问题,我应该写一种方法 如果x * x可以容纳32位整数,则返回1,否则返回0。
我以为我可以检查数字是否大于46340(可以使用2的补码二进制表示形式表示的最大数字的平方根。)但是我不能,因为我限于使用最大255。

 /*
 * squaredOK - Return 1 if x*x can 
fit 
 in 
 a 32-bit integer, and 0 otherwise.
  *  Examples: squaredOK(10) = 1
 *            squaredOK(1000000) = 0
 *  Legal ops: ! ~ & ^ | + - << >>
 *  Max ops: 20
 */
int squaredOK(int x) {

return ; /* no idea */
}

好吧,阅读评论后,我决定添加限制: 仅使用以下内容:

  • 整数常量0到255(0xFF),包括两端。不允许使用大常量,例如0xffffffff。
  • 函数参数和局部变量(无全局变量)。
  • 一元整数运算! 〜
  • 二进制整数运算&^ | + << >>

4 个答案:

答案 0 :(得分:0)

根据代码注释,允许使用<<|,因此您可以使用shift和or来产生一个更大的常量。这在将数字转换为十六进制时更简单:< / p>

 46340 == 0xb504 == (0xB5 << 8) | 0x04

这不能完全解决问题,因为您似乎没有可用的比较(此限制在以后添加)。

在这种情况下,我希望这个问题是针对无符号整数的。在这里,您只需要检查是否设置了16个高位。幸运的是,!在允许的操作列表中,因此您可以仅对右移16的数字不应用。

如果问题实际上出在带符号的数字上,那就更棘手了。您可以使用-和一个检查符号位来替换比较运算符:

int squaredOK(int x) {
   return (x - ((0xB5 << 8) | 4)) >> 31 
}

为了更加安全,您可以使用双精度not(!!)来防止带有符号数字的实现特定的右移行为。

答案 1 :(得分:0)

这个问题的定义模糊不清,我认为您已经以某种方式对其进行了解释,这使您自己变得比需要困难。

如果将“适合32位整数”解释为 unsigned 32位整数,则最大值(2 32 )的平方根为更方便的值(2 16 )。我很确定这就是原意。

答案 2 :(得分:0)

您要实施abs(x) < 46341(或0xb505)但有一些愚蠢的限制。

对于带符号的32位int来说,这个问题似乎非常困难,对于普通的int来说,甚至更困难。

如果问题的格式错误并且适用于32位无符号整数,则可以采用以下解决方案:

 /*
  * squaredOK - Return 1 if x*x can fit in a 32-bit integer, and 0 otherwise.
  *  Examples: squaredOK(10) = 1
  *            squaredOK(1000000) = 0
  *  Legal ops: ! ~ & ^ | + - << >>
  *  Max ops: 20
  */
int squaredOK(uint32_t x) {
    return !(x >> 16);
}

如果该问题确实适用于带有二进制补码表示法的32位带符号的int,则可以验证它是否适用于所有值:

#include <limits.h>
#include <stdio.h>
#include <stdint.h>

int squaredOK(int32_t x) {
    return !(x + 0U >> 31) & x - (0xB5 << 8 | 5U) >> 31 |
           x + 0U >> 31 & !(x + (0xB5 << 8 | 4U) >> 31);
}

int main() {
    long long x;
    for (x = INT32_MIN; x <= INT32_MAX; x++) {
        if (squaredOK(x) != (x * x <= INT32_MAX)) {
            printf("failed on %lld\n", x);
            return 1;
        }
    }
    return 0;
}

说明:

x < 46341 && x > -46341
(x >= 0 && x < 46341) || (x < 0 && x > -46341)
(x >= 0 && x - 46341 < 0) || (x < 0 && x + 46340 >= 0)
(x >= 0 && x - (0xB5<<8|5) < 0) | (x < 0 && x + (0xB5<<8|4) >= 0)
(!(x+0U>>31) & (x - (0xB5<<8|5U)) >> 31) | ((x+0U>>31) & !((x + (0xB5<<8|4U)) >> 31)

通过转换为unsigned并右移31位来测试符号位。 转换为unsigned是隐式的,其中一个操作数是无符号的,因此x + 0Ux转换为无符号类型。其他表达式也使用类似的技巧。

答案 3 :(得分:-1)

答案假定未签名,请针对您的特定作业进行修改

如果在第三个或第四个字节上设置了任何位,则您无法容纳它,因此您的老师想要的是这样的东西:

          //check the third byte for bits      //check the 4th byte for bits
retbool = (((unsigned char)(x >> 16) & 0xFF) | ((unsigned char)(x >> 24) & 0xFF)));

如果设置了这些字节中的任何位,那么您将无法在32位int中拟合平方。如果问题是关于unsigned int 32的话,那将是结尾,但是由于0xFFFF * 0xFFFF大于maxsigned int,因此还必须使用符号位对第二个字节进行一些检查。

由于您永远不可能真的有一个负平方,因此未签名的版本应该是替代答案,但我没有写此作业。

编辑(如果位模式是唯一的,则必须屏蔽...)

#include <stdio.h>

int doesFit(int x);

typedef unsigned char uchar;
typedef unsigned short ushort;

#define MAX_POS_SQUARE 46340
#define MAX_NEG_SQUARE -46340

int main(void) {
    int x=MAX_NEG_SQUARE -2;
    int fits = -1;
    int prevoiusly_fit = 0;
    for(;x<MAX_POS_SQUARE+5;x++){
        fits = doesFit(x);
        if(!fits && prevoiusly_fit){
            printf("%d didnt fit and %d did\n",x,x-1);
        }
        else if(fits && !prevoiusly_fit){
            printf("%d fit and %d did not\n",x,x-1);
        }
        prevoiusly_fit = fits;
    }
    return 0;
}

int doesFit(int x){
    uchar bits_left = 16;
    ushort pos_mask = ((0xb5 << 8) | 0x04);
    ushort neg_mask = ((0xb5 << 8) | 0x05);
    ushort x_16_low = (((-x) & 0xff << 8 ) | (-x) & 0xff); //used in negative case
    ushort x_16_high = (-x)>>16; //used in negative case
    //Handle the negative case
    //printf("0x%04x x: 0x%04x x_16_low: 0x%04x x_16_high:", x, x_16_low, x_16_high);
    if(x>>31){
    //how can you tell if a value x < -46340
        if( (x_16_high & 0xFF) | (x_16_high >>8 & 0xFF)){
            //doesnt fit, maybe dont use compliment use ! if accidental promotion occurs
            printf("bailing out when x=%d\n", x);
            return 0;
        }
        while(bits_left){
            --bits_left;
            if(x_16_low & (1 << bits_left)){
                if(!(neg_mask & (1 << bits_left))){
                    return 0;
                }
            } 
            else if(!(x_16_low & (1 << bits_left))){
                if(neg_mask & (1 << bits_left)){
                    return 1;
                }
            }
            //high bits matched with max value bits, cant tell yet, keep masking.
        }
    }
    else{ //handle the positive case
        //how can you tell if a value x > 46340
        if( (x >> 16 & 0xFF) | (x >>24 & 0x7F)){
            //doesnt fit, return false
            return 0;
        }
        while(bits_left){
            --bits_left;
            if(x & (1 << bits_left)){
                if(!(pos_mask & (1 << bits_left))){
                    return 0;
                }
            } 
            else if(!(x & (1 << bits_left))){
                if(pos_mask & (1 << bits_left)){
                    return 1;
                }
            }
            //high bits matched with max value bits, cant tell yet, keep masking.
        }
    }
    return 1; //Must be the exact size to fit to get to this return
}

输出:

-46341适合,而-46342不适合

46341不适合,46340不适合

我觉得我只是在浪费一个小时来做​​这些家伙的功课...