如何找到TMax不使用移位

How to find TMax without using shifts

本文关键字:何找 TMax      更新时间:2023-10-16

Using

 ! ~ & ^ | +

如何确定32位数字是否为TMax?

TMax是最大的,两个的补数。

到目前为止,我的想法是:

int isTMax(int x)
{
  int y = 0;
  x = ~x;
  y = x + x;
  return !y;
}

这只是我尝试过的许多不成功的事情之一,但我就是想不出TMax的一个属性可以让我得到TMax。就像把tmax加到自身上,与所有其他整数相比,它是唯一的。


实际问题如下:

/*
 * isTMax - return 1 if x is the maximum, two's complement number,
 *     and 0 return otherwise. 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */
int isTMax(int x) {
  int y = 0;
  x = ~x;
  y = x + x;
  return !y;
}

int是32位,所以最大符号可能是0x7FFFFFFF

据我所知,如果不知道有符号类型的最大值并进行直接比较,则无法确定特定值是否为该类型的最大值。这是因为有符号表达式在溢出时会经历未定义的行为。如果你的问题有答案,那就意味着存在一个严重的未解决的问题的答案,这个问题已经在SO上浮动了一段时间:如何通过编程确定给定有符号类型的最大值。

花3个小时做这个问题。我知道这是来自csapp的数据实验室,它的最新要求是

1. Integer constants 0 through 255 (0xFF), inclusive. You are
  not allowed to use big constants such as 0xffffffff
....
* isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1

因此,移位算子(<</>>0x7FFFFFFF从接受的答案中被禁止)

下面是我的路:

tdd风格:

isTmax(2147483647) == isTmax(0b011111111111...1) == 1
isTmax(2147483646) == isTmax(0b011111111111...0) == 0
isTmax(-1) == isTmax(0b111111111...1) == 0
isTmax(-2147483648) == isTmax(0b100000000...0) == 0 

返回值应该是01。在c语言中,!对所有非零操作返回0。因此,!是必须的,否则,我们不能保证得到所有数字的0

第一次朴素尝试:

因为0b0111111...1(又名2147483647)是唯一的参数,应该使isTmax返回1, 2147483647 + 1应该是10000000...0(又名-2147483648)

0b011111111...1 xor 0b1000000000...00b11111111111...111。因为我们必须使用!,所以我们希望看到的是0(也就是0b0000000000000...0)。显然,对0b1111111...1应用逻辑而不是(又称!),那么我们将得到0b000000000000):

!(~(x ^ (x + 1))

让我们打印它

void print(int x)
{
     printf("%dn", !(~(x ^ (x + 1))));
}
int main() {
        print (2147483647);
        print(2147483646);
        print(-1);
        print(-2147483648);
}
1

0

1

0

live demo

还不错,只是-1不像我们期望的那样工作。

第二次尝试:

比较-12147483647

11111111111111111111111111111111
01111111111111111111111111111111

我们可以找到-1 + 1 = 02147483647 + 1 = -2147483648。再次强调,我们想要的是diff -12147483647,因为它们都返回1,如上所示。回顾c中逻辑not的属性:所有非零将返回0,因此!-2147483648 == 0!(-1 + 1) != 0。只需将x ^ (x + 1) (x)的左侧部分修改为x + !(x + 1)。如果x是2147483647,则x + !(x + 1)等于x

再次运行:

void print(int x)
{
    printf("%dn", !(~( x + !(x + 1) ^ (x + 1))));
}
int main() {
        print (2147483647);
        print(2147483646);
        print(-1);
        print(-2147483648);
}
1

0

0

0

live demo

完成了!

int isTmax(int x) {

    //add one to x if this is Tmax. If this is Tmax, then this number will become Tmin
    //uses Tmin = Tmax + 1
    int plusOne = x + 1;
    //add to x so desired input becomes 0xFFFFFFFF, which is Umax and also -1
    //uses Umax = 2Tmax + 1
    x = x + plusOne;
    plusOne = !(plusOne);
    //is x is 0xffffffff, then this becomes zero when ~ is used
    x = ~x;
    x = x | plusOne;
    x = !x;
    return x;
}

无移位解。实现利用!(0b01111 + 1 = 0b10000) = 0!(0b11111 + 1 = 0b00000) = 1的属性是特别棘手的。这道题花了我很长时间。

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */
int isTmax(int x) {
  int a = ~((x + 1) ^ x);
  int b = !(x + 1); 
  int c = !(a + b);
  return c;
}

也许是这样的?

0x7FFFFFFF是最大正符号32位二进制补码数。
int isTMax(int x){
    return !(x ^ 0x7FFFFFFF);
}

我不确定,您可能需要将其强制转换为unsigned才能工作

#include <stdio.h>
#include <stdlib.h>
int test(int n) {
  return !(n & 0x80000000) & !~(n | (n + 1));
}
// or just effectively do a comparison
int test2(int n) {
  return !(n ^ 0x7fffffff);
}
int main(int ac, char **av) {
  printf("is%s TMaxn", test(atoi(av[1])) ? "" : " not");
  return 0;
}

如果是最高温度:011111…

然后我们用10000....

我们得到11111....

则我们得到所有0 = 0,!0得到1:

int isTmax(int x) {
  return !(~((1 << 31) ^ x ));
}

根据最新的要求(即没有移位和没有大常量)给出一个简短的答案。

x + 1 = 0x80000000;
x + (x + 1) = 0xffffffff;
!(~(x + (x + 1))) = 1;
/* Only -1 would fail so we need to explicitly exclude it.*/

最终的答案。

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */
int isTmax(int x) {
  int y = x + 1;
  return !!(~x) & !(~(x + y));
}