仅使用按位转换 long 和 int

Casting long and ints just using bitwise

我正在尝试仅使用按位运算符重现以下函数的输出! ~ & ^ | + << >>.

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

我的所有测试都表明所有问题的答案都只有 1。但是告诉您问题是否正确的自动测试器说只返回一个是不正确的。

什么情况下答案不是1? 如果函数没有像这样被复制:

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

正确的 function/expression 是什么(仅使用上述按位运算符)?

以下测试 returns 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 中的最大值,这会导致溢出。您的代码用于测试 int 中的溢出,因此您需要使用导致 int 中的 + 溢出的值对其进行测试。有很多测试表明这种溢出,我的只是一个例子。

更新:

如评论中所述,lsum == (int) lsum 部分代码在 C 中实现定义,因此您根本无法传递函数结果。如果数据类型是无符号的(unsigned intunsigned long long),我的论点是正确的。此代码也是在 C++C++20 之前定义的实现。在C++20之后又在C++定义了

如果 x + y 大于 tmax 或小于 tmin,它应该 return 0。

否则会return1.

也许您正在尝试检查 xy 的相加是否会给出一个有效的结果作为 uint32_t .如评论中所述,问题是如果数字太 "large",则从 uint64_t 到 uint32_t 的转换未定义。

目前,C 和 C++ 都不假定数字表示为二进制补码,因此很难进行这种验证。这将会改变,因为下一个 C++ 标准将强制使用 two's complement to code signed integers(并且 C 标准可能会遵循)。

但这不会为不正确的转换赋予意义,您的代码仍然无效。

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

可以使用多种解决方案。这是一个主要依赖于按位运算符的。

方法大纲是:

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

  • 添加它们。这将计算 x/2+y/2 并且它将等于 (x+y)/2 except 如果 xy 的 LSB 都是 1,在这种情况下会产生权重为 2^ 的进位x+y.
    中的 1 我们通过 anding xy 的 LSB 来测试这个进位的存在,然后我们添加它总和。

  • 前面计算的结果(x+y)/2在32位上总是有效的。我们检查它在 31 位上是否有效。如果为真,x+y 将在 32 位上有效。
    只需比较第 31 位和第 30 位即可检查此有效性。如果它们相等,则可以安全地将结果转换为 31 位。否则,转换将引起符号变化。

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) ) ;
}