我有一个有趣的谜题。我需要从带符号的数字转换,比如说-5(0x80000005)到2的补码-5(0xFFFFFFFB)。我可以使用的唯一操作符是,!,〜,&,^,|,+,<<,>>并且最多15个与我想要的变量任意组合。 =可以使用,不计入运营商总数。此外,不能使用“if”语句,循环或对任何类型的函数的调用。
该功能看起来像
int sign2two(int x){
//... some stuff here
return x;
}
我遇到的问题是我可以查明数字是否为负数。但我想说,如果num为负,则翻转位并添加1.否则返回数字。我无法弄清楚如何做到这一点。感谢。
答案 0 :(得分:2)
我认为这些问题非常愚蠢......
#include <stdint.h>
#include <stdio.h>
int32_t test1(uint32_t x) {
const uint32_t sign = (x & 0x80000000); // Total operations: 1
const uint32_t value = (x & 0x7FFFFFFF); // Total operations: 2
// Let's create a value N, where N is equal to:
// if (sign)
// N = 0xFFFFFFFF;
// else
// N = 0x00000000;
uint32_t N = sign; // Total operations: 2
N = N | (N >> 1); // Total operations: 4
N = N | (N >> 2); // Total operations: 6
N = N | (N >> 4); // Total operations: 8
N = N | (N >> 8); // Total operations: 10
N = N | (N >> 16); // Total operations: 12
// Let's create a value MaybeOne, where MaybeOne is equal to:
// if (sign)
// MaybeOne = 1;
// else
// MaybeOne = 0;
uint32_t MaybeOne = N & 0x1; // Total operations: 13
// Now, Let's perform the following step:
// if (sign)
// return (value ^ 0xFFFFFFFF) + 1;
// else
// return (value ^ 0x00000000) + 0;
return (value ^ N) + MaybeOne; // Total operations: 15
}
int32_t test2(uint32_t x) {
int32_t sign = (x & 0x80000000);
int32_t value = (x & 0x7FFFFFFF);
if (sign)
return -value;
else
return value;
}
int main() {
uint32_t i;
for (i=0; i<0xFFFFFFFF; ++i)
if (test1(i) != test2(i))
printf("0x%08x\n", i);
}
另外,使用Eric Postpischil的评论,我们可以大幅减少操作次数:
int32_t test3(uint32_t x) {
const uint32_t sign = (x >> 31); // Total operations: 1
const uint32_t value = (x & 0x7FFFFFFF); // Total operations: 2
// Let's create a value N, where N is equal to:
// if (sign)
// N = 0xFFFFFFFF;
// else
// N = 0x00000000;
const uint32_t N = ~sign + 1; // Total operations: 4
// Let's create a value MaybeOne, where MaybeOne is equal to:
// if (sign)
// MaybeOne = 1;
// else
// MaybeOne = 0;
uint32_t MaybeOne = sign; // Total operations: 4
// Now, Let's perform the following step:
// if (sign)
// return (value ^ 0xFFFFFFFF) + 1;
// else
// return (value ^ 0x00000000) + 0;
return (value ^ N) + MaybeOne; // Total operations: 6
}
答案 1 :(得分:2)
您没有可用的条件,但您可以屏蔽。根据符号的值创建掩码有不同的方法。
以下使用 Eric Postpischil 的非常好的提示!
如果符号为0(即为正),则掩码将变为0,否则它仍然是您需要的值 - &gt;条件无条件
#include <stdarg.h>
#include <stdio.h>
int sign2two(unsigned int a){
int sign = a>>31; // alternative: sign = !!((a<<1>>1)+~a+1); see below
unsigned int withoutSign = a << 1 >> 1;
unsigned int mask = ~sign +1;
printf("withoutSign is: %u\nsign is: %u\nmask is: %x\n",
withoutSign, sign, mask);
unsigned int temp = (withoutSign^mask)+sign;
return *(int*)&temp;
}
void printSign2two(unsigned int a){
printf("the 2s complement number: %i\n\n", sign2two(a));
}
int main(){
printSign2two(0x00000005);
printSign2two(0x80000005);
return 0;
}
输出:
withoutSign is: 5
sign is: 0
mask is: 0
the 2s complement number: 5
withoutSign is: 5
sign is: 1
mask is: ffffffff
the 2s complement number: -5
关于sign = !!((a<<1>>1)+~a+1);
的 注意。这使用了比sign = a>>31
更多的运算符,但它与32/64位数无关。
<<1>>1
清除最重要的位,-a
不允许,我们会使用+~a+1
(再次感谢 Eric Postpischil )答案 2 :(得分:1)
要将Sign Magnitude x转换为Two's Complement y:
1)在双补机上
2)仅使用!,〜,&amp;,^,|,+,&lt;&lt;,&gt;&gt;
3)不使用?:, - ,*,/
4)不假设4字节int
5)适用于所有Sign Magnitude整数,包括+0和-0
#include <limits.h>
int sm2tc(int x) {
int sign = x & INT_MIN;
int negmask = UINT_MAX + !sign;
return (x & ~negmask) | (negmask & ((~x + 1)^INT_MIN));
}
这个答案是一个重复的问题How to convert from sign-magnitude to two's complement,其选定的答案不符合OP规定的考虑操作限制的标准。