C 仅使用按位转换long和int

C 仅使用按位转换long和int,c,bit-manipulation,bitwise-operators,C,Bit Manipulation,Bitwise Operators,我试图仅使用位运算符来重现以下函数的输出!~&^ |+> 我所有的测试都表明所有问题的答案都是1。然而,自动测试仪告诉你一个问题是否正确,只返回一个是不正确的 在什么情况下,答案不是1? 如果功能没有像这样复制: int test_dl2(int x, int y) { return 1; } 正确的函数/表达式是什么(仅使用上述位运算符)?以下测试为您的函数返回0: #include <stdio.h> #include <limits.h> int tes

我试图仅使用位运算符来重现以下函数的输出!~&^ |+>

我所有的测试都表明所有问题的答案都是1。然而,自动测试仪告诉你一个问题是否正确,只返回一个是不正确的

在什么情况下,答案不是1? 如果功能没有像这样复制:

int test_dl2(int x, int y) { 
   return 1;
}

正确的函数/表达式是什么(仅使用上述位运算符)?

以下测试为您的函数返回
0

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

int test_dl2(int x, int y) { 
   long long lsum = (long long) x + y;
   return lsum == (int) lsum;
}

int main() {
    printf("%d", test_dl2(INT_MAX, 1));
    return 0;
}
#包括
#包括
int test_dl2(int x,int y){
长lsum=(长)x+y;
返回lsum==(int)lsum;
}
int main(){
printf(“%d”,test_dl2(INT_MAX,1));
返回0;
}
我使用的数字是导致溢出的最大值
int
。您的代码用于测试
int
中的溢出,因此您需要使用导致
int
+
中溢出的值来测试它。有很多测试显示这种溢出,我的只是一个例子

更新:


如注释中所述,
lsum==(int)lsum
部分位于
C
中定义的实现中的代码中,因此您根本无法在函数结果中进行中继。如果数据类型为无符号(
unsigned int
unsigned long
),则我的参数是正确的。此代码也是在
C++
中定义的实现,直到
C++20
。在
C++20
之后,它再次在
C++
中定义。

以下测试为您的函数返回
0

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

int test_dl2(int x, int y) { 
   long long lsum = (long long) x + y;
   return lsum == (int) lsum;
}

int main() {
    printf("%d", test_dl2(INT_MAX, 1));
    return 0;
}
#包括
#包括
int test_dl2(int x,int y){
长lsum=(长)x+y;
返回lsum==(int)lsum;
}
int main(){
printf(“%d”,test_dl2(INT_MAX,1));
返回0;
}
我使用的数字是导致溢出的最大值
int
。您的代码用于测试
int
中的溢出,因此您需要使用导致
int
+
中溢出的值来测试它。有很多测试显示这种溢出,我的只是一个例子

更新:


如注释中所述,
lsum==(int)lsum
部分位于
C
中定义的实现中的代码中,因此您根本无法在函数结果中进行中继。如果数据类型为无符号(
unsigned int
unsigned long
),则我的参数是正确的。此代码也是在
C++
中定义的实现,直到
C++20
。在
C++20
之后,再次在
C++
中定义它。

如果x+y大于tmax或小于tmin,则应返回0


否则它将返回1。

如果x+y大于tmax或小于tmin,它应返回0


否则它将返回1。

可能您正在尝试检查x和y的相加是否会作为uint32\t给出有效的结果。如评论中所述,问题在于,如果数字太大,则从uint64_t到uint32_t的转换未定义

目前,C和C++都不认为数字表示为两个补码,使得这种验证困难。随着下一个C++标准将强制使用(并且可能C标准将遵循),这将发生变化。 但这并不能说明错误转换的意义,您的代码仍然无效

如果我们假设数字是以2的补码编码的(这已经是大多数计算机的行为),那么可以进行一些测试

可以使用几种解决方案。这里有一个主要依赖于位运算符的

该方法概述如下:

  • 左移数字除以二(假设符号上的左移是算术运算,这在大多数计算机上是正确的,但目前标准不要求)

  • 添加它们。这将计算x/2+y/2,它将等于(x+y)/2,除非如果x和y的LSB都是1,在这种情况下,在x+y中的权重为2^1时生成进位。
    我们通过对x和y的LSB求和来检验这个进位的存在性,并将它加到和中

  • 先前计算的结果(x+y)/2在32位上始终有效。我们检查它在31位上是否有效。如果为真,则x+y在32位上有效。
    通过比较位31和30,可以简单地检查该有效性。如果它们相等,则可以在31位上安全地转换结果。否则,转换将导致符号变化

int是有效的(uint32\utx,uint32\uty){
uint32_t z=(x>>1)+(y>>1)+(x&y&0x1);

return!((z^(z可能您正在尝试检查x和y的相加是否会给出作为uint32_t的有效结果。问题是,如注释中所述,如果数字太大,则从uint64_t到uint32_t的转换未定义

目前,C和C++都不认为数字表示为两个补码,使得这种验证变得困难。随着下一个C++标准将强制使用(并且可能的C标准将遵循),这将发生变化。 但这并不能说明错误转换的意义,您的代码仍然无效

如果我们假设数字是以2的补码编码的(这已经是大多数计算机的行为),那么可以进行一些测试

可以使用几种解决方案。下面是一种主要依赖于位运算符的解决方案

该方法概述如下:

  • 左移数字除以二(假设符号上的左移是算术运算,这在大多数计算机上是正确的,但目前标准不要求)

  • 将它们相加。这将计算x/2+y/2,它将等于(x+y)/2,除非如果x和y的LSB都是1,在这种情况下,在x+y中的权重为2^1时生成进位。
    我们测试th
    int is_add32_valid(uint32_t x, uint32_t y) { 
      uint32_t z = (x>>1) + (y>>1) + (x & y & 0x1) ;
      return !( (z ^ (z <<1)) & (1 << 31) ) ;
    }