Language agnostic 如何在一个字节中反转ON位?

Language agnostic 如何在一个字节中反转ON位?,language-agnostic,Language Agnostic,我在读乔尔的书,他在书中提出了一个采访问题: 编写一个程序来反转给定字节中的“开”位 我只能想到一个使用C的解决方案 在这里提问,以便您可以向我展示如何以非C的方式进行操作(如果可能)该问题的具体含义是什么 相反是否意味着将1设置为0,反之亦然 或者它是指000011100-->00110000,在字节中反转它们的顺序?或者可能只是将前一个1的部分反转到最后一个1?即00110101-->00101011 假设这意味着颠倒整个字节的位顺序,下面是x86汇编程序版本: ; al is input

我在读乔尔的书,他在书中提出了一个采访问题:

编写一个程序来反转给定字节中的“开”位

我只能想到一个使用C的解决方案


在这里提问,以便您可以向我展示如何以非C的方式进行操作(如果可能)

该问题的具体含义是什么

相反是否意味着将1设置为0,反之亦然

或者它是指000011100-->00110000,在字节中反转它们的顺序?或者可能只是将前一个1的部分反转到最后一个1?即00110101-->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

不是最理想的解决方案,查表更快。

颠倒C#中的位顺序:

字节反向字节(字节b)
{
字节r=0;
对于(int i=0;i i;
int reversedMask=bit经典页面有几种(非常聪明的)方法来实现这一点,但都是用C语言实现的。任何从C语法派生的语言(尤其是Java)都可能有类似的方法。我相信我们会在这个线程中得到一些Haskell版本;)

字节反向字节(字节b)
{
返回b^0xff;
}

如果在您的语言中,
^
是XOR,那么这是可行的,但如果它是
(通常是这样)就不行了


这个问题具体是什么意思

好问题。如果反转“开”位意味着只反转“开”位,则无论输入是什么,都将始终得到0。如果这意味着反转所有位,即将所有1更改为0,将所有0更改为1,这是我最初读取它的方式,那么这只是按位非或补码。基于C的语言有一个补码运算符,
~
,可以实现此目的。例如:

unsigned char b = 102;      /* 0x66, 01100110 */
unsigned char reverse = ~b; /* 0x99, 10011001 */

如果您正在谈论使用Ruby将1切换到0,将0切换到1:

n = 0b11001100
~n
如果你的意思是颠倒顺序:

n = 0b11001100
eval("0b" + n.to_s(2).reverse)
如果您的意思是计算位,如另一个用户所述:

n = 123
count = 0
0.upto(8) { |i| count = count + n[i] }

♥ Ruby

我可能记错了,但我认为Joel的问题是计算“on”位,而不是反转它们。

因为问题要求非C方式,下面是一个方案实现,愉快地抄袭了:

重写为C(对于不熟悉Scheme的人),它看起来是这样的(在Scheme中,数字可以任意大):

int
反向位(整数k,整数n)
{
int m=n<0?~n:n;
int-rvs=0;
而(-k>=0){
rvs=(rvs>=1;
}
返回n<0?~rvs:rvs;
}
int
反向位字段(整数n、整数开始、整数结束)
{
int width=结束-开始;
int mask=~-1>开始;

return(bit_reverse(width,zn)这里有一个直接剪切粘贴的版本,这很有趣,因为它不涉及循环。另一方面,与我发布的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;
}
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;
}
公共静态int反转(int i){
//HD,图7-1
i=(i&0x555555)>>1)和0x555555;
i=(i&0x33333333)>>2)和0x33333333;
i=(i&0x0f0f)>>4)和0x0f0f;
i=(i>8)&0xff00)|(i>>24);
返回i;
}
64位版本:

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;
}
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;
}
公共静态长反转(长i){
//HD,图7-1
i=(i&0x555555L)>>1)和0x555555L;
i=(i&0x3333L)>>2)和0x3333L;
i=(i&0x0F0FL)>>4)和0x0F0FL;
i=(i&0x00ff00ff00ff00ff00ffl)>>8)和0x00ff00ff00ff00ffL;
i=(i>16)&0xffff0000L)|(i>>>48);
返回i;
}

我可能记错了,但我 我以为乔尔的问题是关于 计算“开”位而不是 逆转它们

给你:

#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;
}
#包括
int countBits(无符号字符字节);
int main(){
FILE*out=fopen(“bitcount.c”、“w”);
int i;
fprintf(out,“#include\n#include\n#include\n\n”);
fprintf(out,“int位计数[256]={”);

对于(i=0;i,这里是用于补充位的强制性Haskell soln,它使用库函数complete:

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)]

我将修改palmsey的第二个示例,消除一个bug并消除
eval

n = 0b11001100
n.to_s(2).rjust(8, '0').reverse.to_i(2)

如果要按位反转的数字是一个固定长度的位字段,
rjust
非常重要——如果没有它,
0b00101010
的反转将是
0b10101
,而不是正确的
0b01010100
(显然,应该用所讨论的长度替换8)我刚刚被这个问题绊倒了。

如果这个问题意味着翻转所有位,并且不允许使用类似C的运算符,例如XOR和NOT,那么这将起作用:

bFlipped = -1 - bInput;
我提出了一个技巧问题:)反转所有位意味着一个触发器,但只有打开的位清楚地表示:

return 0;
伪代码

while (Read())
  Write(0);
在这里提问,以便您可以向我展示如何以非C方式进行操作(如果可能)

假设您的号码是10101010。要将1s更改为0s(反之亦然),只需使用XOR:

 10101010
^11111111
 --------
 01010101
用手做这件事就像你会得到的“非C”

然而,从问题的措辞来看,它听起来似乎只是关闭了“开启”位……在这种情况下,答案是零(正如已经提到的)(当然,除非问题实际上是要求交换位的顺序)。

反转位。 例如,我们有一个由011011表示的数字。现在如果我们反转位,那么这个数字将变成11010110。现在要实现这一点,您应该首先知道如何交换一个数字中的两个位。 交换数字中的两位:- 用一对两位进行异或运算,看结果是否不同。如果结果不一样,则两位相同,否则用异或运算对两位进行异或运算,并将其保存在原始数字中; 现在来倒数 对于小于Numberofbits/2的I
交换(Number,I,NumberOfBits-1-I);

对所有1进行异或。
 10101010
^11111111
 --------
 01010101