仅使用按位转换 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 int
和 unsigned long long
),我的论点是正确的。此代码也是在 C++
中 C++20
之前定义的实现。在C++20
之后又在C++
定义了
如果 x + y 大于 tmax 或小于 tmin,它应该 return 0。
否则会return1.
也许您正在尝试检查 x 和 y 的相加是否会给出一个有效的结果作为 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 如果 x 和 y 的 LSB 都是 1,在这种情况下会产生权重为 2^ 的进位x+y.
中的 1
我们通过 anding x 和 y 的 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) ) ;
}
我正在尝试仅使用按位运算符重现以下函数的输出! ~ & ^ | + << >>.
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 int
和 unsigned long long
),我的论点是正确的。此代码也是在 C++
中 C++20
之前定义的实现。在C++20
之后又在C++
定义了
如果 x + y 大于 tmax 或小于 tmin,它应该 return 0。
否则会return1.
也许您正在尝试检查 x 和 y 的相加是否会给出一个有效的结果作为 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 如果 x 和 y 的 LSB 都是 1,在这种情况下会产生权重为 2^ 的进位x+y.
中的 1 我们通过 anding x 和 y 的 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) ) ;
}