我正在读Joel的书,他在那里提出了面试问题:
编写程序以反转给定字节中的“ON”位。
我只能想到使用C的解决方案。
在这里询问,这样你就可以告诉我如何用Non C方式(如果可能的话)
答案 0 :(得分:21)
我主张技巧问题。 :)反转所有位意味着触发器,但只有明显的位意味着:
return 0;
答案 1 :(得分:14)
这个问题的具体含义是什么?
好问题。如果反转“ON”位意味着仅反转“ON”位,那么无论输入是什么,您总是会得到0。如果它意味着反转 all 这些位,即将所有1改为0并将所有0改为1,这是我最初读取它的方式,那么这只是一个按位NOT或补码。基于C语言的补充运算符~
就是这样做的。例如:
unsigned char b = 102; /* 0x66, 01100110 */
unsigned char reverse = ~b; /* 0x99, 10011001 */
答案 2 :(得分:4)
反转C#中的位顺序:
byte ReverseByte(byte b)
{
byte r = 0;
for(int i=0; i<8; i++)
{
int mask = 1 << i;
int bit = (b & mask) >> i;
int reversedMask = bit << (7 - i);
r |= (byte)reversedMask;
}
return r;
}
我确信有更聪明的方法可以做到这一点,但在这个精确的情况下,面试问题是为了确定你是否知道按位操作,所以我猜这个解决方案是可行的。
在一次采访中,面试官通常想知道你是如何找到解决方案的,你解决问题的技巧是什么,如果它是干净的还是黑客攻击。因此,不要提出太多聪明的解决方案,因为可能意味着您事先在互联网上找到了它。不要试图假装你也不知道它,并且你只是想出答案,因为你是天才,如果她弄清楚,因为你基本上是在撒谎,这将是最糟糕的。
答案 3 :(得分:4)
这个问题的具体含义是什么?
反向是否将1设置为0,反之亦然?
或者是否意味着 00001100 - &gt; 00110000 你在字节中反转它们的顺序?或者也许只是将第一个1到最后一个的部分反转?即。 00110101 - &gt; 00101011
假设它意味着在整个字节中反转位顺序,这里是一个x86汇编程序版本:
; al is input register
; bl is output register
xor bl, bl ; clear output
; first bit
rcl al, 1 ; rotate al through carry
rcr bl, 1 ; rotate carry into bl
; duplicate above 2-line statements 7 more times for the other bits
不是最佳解决方案,表查找速度更快。
答案 4 :(得分:3)
如果您正在谈论将1转换为0,将0转换为1,则使用Ruby:
n = 0b11001100
~n
如果您的意思是颠倒顺序:
n = 0b11001100
eval("0b" + n.to_s(2).reverse)
如果你的意思是计算其他用户提到的on位:
n = 123
count = 0
0.upto(8) { |i| count = count + n[i] }
♥Ruby
答案 5 :(得分:3)
我可能记错了,但是我 以为乔尔的问题是关于 计算“开”位而不是 扭转它们。
你走了:
#include <stdio.h>
int countBits(unsigned char byte);
int main(){
FILE* out = fopen( "bitcount.c" ,"w");
int i;
fprintf(out, "#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n\n");
fprintf(out, "int bitcount[256] = {");
for(i=0;i<256;i++){
fprintf(out, "%i", countBits((unsigned char)i));
if( i < 255 ) fprintf(out, ", ");
}
fprintf(out, "};\n\n");
fprintf(out, "int main(){\n");
fprintf(out, "srand ( time(NULL) );\n");
fprintf(out, "\tint num = rand() %% 256;\n");
fprintf(out, "\tprintf(\"The byte %%i has %%i bits set to ON.\\n\", num, bitcount[num]);\n");
fprintf(out, "\treturn 0;\n");
fprintf(out, "}\n");
fclose(out);
return 0;
}
int countBits(unsigned char byte){
unsigned char mask = 1;
int count = 0;
while(mask){
if( mask&byte ) count++;
mask <<= 1;
}
return count;
}
答案 6 :(得分:2)
这是一个直接从OpenJDK剪切和粘贴的版本,这很有趣,因为它不涉及循环。另一方面,与我发布的Scheme版本不同,此版本仅适用于32位和64位数字。 : - )
32位版本:
public static int reverse(int i) {
// HD, Figure 7-1
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
64位版本:
public static long reverse(long i) {
// HD, Figure 7-1
i = (i & 0x5555555555555555L) << 1 | (i >>> 1) & 0x5555555555555555L;
i = (i & 0x3333333333333333L) << 2 | (i >>> 2) & 0x3333333333333333L;
i = (i & 0x0f0f0f0f0f0f0f0fL) << 4 | (i >>> 4) & 0x0f0f0f0f0f0f0f0fL;
i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
i = (i << 48) | ((i & 0xffff0000L) << 16) |
((i >>> 16) & 0xffff0000L) | (i >>> 48);
return i;
}
答案 7 :(得分:2)
伪代码..
while (Read())
Write(0);
答案 8 :(得分:2)
byte ReverseByte(byte b) { return b ^ 0xff; }
如果^
在你的语言中是异或的,那么这是有效的,但如果它是AND
,则通常是这样的。
答案 9 :(得分:2)
经典的Bit Hacks页面有几种(非常聪明的)方法可以做到这一点,但它都在C语言中。任何从C语法(特别是Java)派生的语言都可能有类似的方法。我相信我们会在这个帖子中得到一些Haskell版本;)
答案 10 :(得分:1)
我可能记错了,但我认为Joel的问题是计算“on”位而不是反转它们。
答案 11 :(得分:1)
这是用于补充位的强制性Haskell soln,它使用库函数,补码:
import Data.Bits
import Data.Int
i = 123::Int
i32 = 123::Int32
i64 = 123::Int64
var2 = 123::Integer
test1 = sho i
test2 = sho i32
test3 = sho i64
test4 = sho var2 -- Exception
sho i = putStrLn $ showBits i ++ "\n" ++ (showBits $complement i)
showBits v = concatMap f (showBits2 v) where
f False = "0"
f True = "1"
showBits2 v = map (testBit v) [0..(bitSize v - 1)]
答案 12 :(得分:1)
我修改了palmsey的第二个例子,消除了一个错误并消除了eval
:
n = 0b11001100
n.to_s(2).rjust(8, '0').reverse.to_i(2)
如果要按位反转的数字是固定长度的位字段,rjust
很重要 - 没有它,0b00101010
的反转将是0b10101
而不是正确的0b01010100
。 (显然,8应该用有问题的长度代替。)我刚被这个绊倒了。
答案 13 :(得分:1)
如果问题意味着翻转所有位,并且不允许使用类似C的运算符,例如XOR和NOT,那么这将起作用:
bFlipped = -1 - bInput;
答案 14 :(得分:1)
在这里询问,这样你就可以用非C方式(如果可能的话)告诉我怎么做
假设您的号码为10101010.要将1更改为0(反之亦然),您只需使用XOR:
10101010
^11111111
--------
01010101
手工操作就像你得到的“非C”一样。
然而,根据问题的措辞,它听起来似乎只关闭“ON”位...在这种情况下答案是零(如已经提到的那样)(当然除外)问题实际上是要求交换位的顺序。)
答案 15 :(得分:0)
由于问题是非C方式,这是一个方案实施,从SLIB高兴地抄袭:
(define (bit-reverse k n)
(do ((m (if (negative? n) (lognot n) n) (arithmetic-shift m -1))
(k (+ -1 k) (+ -1 k))
(rvs 0 (logior (arithmetic-shift rvs 1) (logand 1 m))))
((negative? k) (if (negative? n) (lognot rvs) rvs))))
(define (reverse-bit-field n start end)
(define width (- end start))
(let ((mask (lognot (ash -1 width))))
(define zn (logand mask (arithmetic-shift n (- start))))
(logior (arithmetic-shift (bit-reverse width zn) start)
(logand (lognot (ash mask start)) n))))
重写为C(对于不熟悉Scheme的人),它看起来像这样(理解在Scheme中,数字可以任意大):
int
bit_reverse(int k, int n)
{
int m = n < 0 ? ~n : n;
int rvs = 0;
while (--k >= 0) {
rvs = (rvs << 1) | (m & 1);
m >>= 1;
}
return n < 0 ? ~rvs : rvs;
}
int
reverse_bit_field(int n, int start, int end)
{
int width = end - start;
int mask = ~(-1 << width);
int zn = mask & (n >> start);
return (bit_reverse(width, zn) << start) | (~(mask << start) & n);
}
答案 16 :(得分:0)
反转位。 例如,我们有一个由01101011表示的数字。现在,如果我们反转这些位,那么这个数字将变为11010110.现在要实现这一点,你应该首先知道如何在一个数字中交换两位。 在一个数字中交换两位: - 将这两个位与一个XOR进行异或,看看结果是否不同。如果它们不是,那么两个位都是相同的,否则将具有XOR的位都异或并保存在其原始数字中; 现在为了扭转这个数字 因为我比Numberofbits / 2少 交换(数量,I,NumberOfBits-1-I);